前言
最近在公司需要对导出各种类型的报表进行一个性能优化(主要是防止溢出),然后要对性能优化的话肯定要先对当前的性能进行排查,然后对于这篇文章的话主要是写个开头,说明一下如何计算JAVA对象的内存占用大小
目录
1.对象占用内存的基本组成结构
2.对象的占用内存计算
3.第三方内存大小计算工具
对象占用内存的基本组成结构
对象内存占用计算
以下面类为例
class People{
int age = 20;
String name = "Xiaoming";
}
class Person extends People{
boolean married = false;
long birthday = 128902093242L;
char tag = 'c';
double sallary = 1200.00d;
}
计算Person的内存占用对象(bytes),例子用32位计算器(若64位且不指针压缩则需要重新计算mark word和引用对象)
实例数据:
对象头:
4(mark) + 4(klass) = 8
实例数据:
4(age) + 4(name(ref)) + 1(married) + 8(birthday) + 2(tag) + 8(sallary) = 27
要注意的是,name为引用类型,还需要计算引用类型的实际大小
// 然后String源码又是这样的
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
并且字符串又是引用char[]数组进行计算的,则也要继续往下计算
name表层:对象头8个字节 + hash(4) + serialVersionUID(8) + 4(char[]) = 24
然后计算char[] = 对象头8个字节 +数组的length(4) + char(2) * 8 = 28
目前Person总大小为
对象头 + 实例数据 = 87
然后由于字段的需要是8个字节的倍数,所以需要计算padding
总大小为: 对象头 + 实例数据 + padding = 88
第三方内存大小计算工具
以计算CellData对象为例(自己产品的对象)
1.编写main方法创建对象
public class testCalc {
public static void main (String[] args) throws InterruptedException {
CellData cellData = new CellData();
System.out.println("启动开始计算");
// 这个sleep就是为了当前java线程一直存在
Thread.sleep(1000 * 3600);
System.out.println(cellData);
}
}
2.打开cmd,找到当前执行的java线程
直接在cmd中输入 jsp找到当前线程编号
3.打开HSDB工具
找到路径jdk\lib,在当前路径打开cmd,输入
4.在HSDB中打开当前java线程
注意:若出现以下两个问题,相对应解决就好
1.Exception in thread “Thread-1” java.lang.UnsatisfiedLinkError: Can’t load library: JRE_PATH\bin\sawindbg.dll
解决方法:从jdk/jre/bin/下面复制一个sawindbg.dll到jre/bin路径下即可
2.could not fined symol ‘gHotSpotVMTypes’
解决方法:这个时候就是说明你运行类的jdk和你环境变量的jdk版本不一样,比如你运行类的jdk为1.7,但是环境变量的jdk为1.8,这个时候就会版本不对称导致出现错误了,把版本弄成一样的就好了
5.使用tool找到当前类