通常情况下Hotspot虚拟机里Heap(堆)中的Java对象占用的内存包括:
Object Header占用的内存,普通对象的Object Header占用8个字节的内存,数组对象的Object Header占用12个字节的内存(其中的4个字节用于存储数组的长度)
成员变量占用的内存
基本数据类型的成员变量(primitive field),boolean/byte类型耗用1个字节,char/short类型耗用2个字节,int/float类型耗用4个字节,long/double类型耗用8个字节
对象类型的成员变量(reference field),每个变量一个4个字节的reference
Padding(对齐)需要的额外内存,padding部分是紧跟在object data后面的若干(0~7)个字节,使得整个对象耗用的字节数能被8整除。
于是对象占用的内存大小可以用下面的公式进行估算:
sizeof(obj) = ceil((sizeof(object header) + sum(sizeof(primitive field)) + 4*num(reference field))/8)*8
例如,对于下面一个Class:
class MyClass { // 8 bytes (object header)
byte a; // 1 byte
int c; // 4 bytes
boolean d; // 1 byte
long e; // 8 bytes
Object f; // 4 bytes (reference)
}
不考虑padding(对齐)的情况下该类的实例大约占用26(8 + 1 + 4 + 1 + 8 + 4)个字节,进行padding后将占用32个字节的空间。
注意:这里估算的内存占用大小并不包括对象类型的成员变量所占用的内存大小,这里只计算reference占用的内存大小。
一维数组的内存占用量:
在Java里数组也是对象,且数组对象的Object Header比普通对象的要多4个字节,这4个字节是用来存储数组长度用的。另外数组对象也会被Padding(补齐)。
基本数据类型的数组对象占用的内存大小可以用下面的公式进行估算:
sizeof(array) = ceil((12 + sizeof(primitive field)*m)/8)*8 #m为数组的长度
如长度为10的int类型的数组int[10]占用的内存大小为: ceil((12 + 4*10)/8)*8 = 56
对象数组Object[]占用的内存大小可以用下面的公式进行估算:
sizeof(Object[]) = ceil((12 + 4*m)/8)*8
4*m中的4表示每个Object reference占用的内存大小,4个字节;m表示数组的长度。
再例如,对于String类:
public final class String { // 8 bytes (object header)
private final char value[]; // 4 bytes (reference)
private final int offset; // 4 bytes
private final int count; // 4 bytes
private int hash; // 4 bytes
}
一个包含n个字符的String对象整体(包括char[]数组)占用的内存大小为:
sizeof(string) = ceil((8 + 4 + 4 + 4 + 4)/8)*8 + ceil((12 + 2*n)/8)*8
二维数组的内存占用量:
Java中的二维(多维)数组与C语言中的二维(多维)数组有非常大的不同。Java中的二维(多维)数组是由nested数组构成的一个级联结构,二维(多维)数组中的每一行都是一个reference指向的nested数组。
于是对于一个m*n的二维数组array[m][n],它的内存占用量包括下面两部分:
1个长度为m的外层数组占用的内存,可以表示为:ceil((12 + 4*m)/8)*8
m个长度为n的内存数组占用的内存,可以表示为:m*(ceil((12 + sizeof(nested_array_type)*n)/8)*8)
对于基本数据类型的二维数组,sizeof(nested_array_type)为对应基本数据类型的内存使用量
对于Object[][],sizeof(nested_array_type)等于4个字节,即reference的内存使用量
例如,对于int类型的二维数组int[m][n],它的内存占用量估算为:
ceil((12 + 4*m)/8)*8 + m*(ceil((12 + 4*n)/8)*8)
假设(m=1000000, n=3),则该二维数组的内存占用量为:
ceil((12 + 4*1000000)/8)*8 + 1000000*(ceil((12 + 4*3)/8)*8) = 28,000,016
结论:尽量避免长期持有(引用)大规模的二维数组对象