环境:64位JVM
1.类实例内存结构
在64位的JVM中字长为64位(8字节),class指针在开启指针压缩的情况下为4个字节(不开启的话为8字节,堆内存小于等于32G默认开启)。数组长度为4字节。因为对象的大小必须为字长(8字节)的倍数,所以需要对齐
JOL类库中的API可以打印对象内存布局
ClassLayout ClassLayout.parseInstance(Object instance)
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
2. 获取对象大小的方法
1. jdk目录中的 jdk\jre\lib\ext\nashorn.jar
jdk.nashorn.internal.ir.debug.ObjectSizeCalculator.getObjectSize(Object obj)
2. Instrumentation接口中的方法,需要使用agent
Instrumentation.getObjectSize(Object objectToSize)
3. JOL中的VirtualMachine.sizeOf(Object obj)方法
VM.current().sizeOf(Integer.parseInt("1"))
JOL的底层也是通过agent来获取Instrumentation,从而得到对象的大小
3. 基本数据类型的大小
整数类型
byte:1字节, short:2字节, int:4字节, long:8字节
浮点型
float:4字节 double:8字节
boolean:1字节
char:2字节
4. 基本类型对应的包装类型的内存布局
class java.lang.Long
java.lang.Long object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf80022f5
12 4 (alignment/padding gap)
16 8 long Long.value 1
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
以Long类型为例:
对象头中:标记字:8字节,class指针:4字节,
对象体:包装的实际类型为long:8字节
对象对齐:4字节。
一共24字节,损失4字节空间
其他包装类型的内存布局ru
class java.lang.Double
java.lang.Double object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf80021d9
12 4 (alignment/padding gap)
16 8 double Double.value 1.0
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
class java.lang.Integer
java.lang.Integer object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000007106e68e01 (hash: 0x7106e68e; age: 0)
8 4 (object header: class) 0xf80022ae
12 4 int Integer.value 1
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
class java.lang.Float
java.lang.Float object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf8002192
12 4 float Float.value 1.0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
class java.lang.Short
java.lang.Short object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf8002267
12 2 short Short.value 1
14 2 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
class java.lang.Character
java.lang.Character object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800210d
12 2 char Character.value a
14 2 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
class java.lang.Boolean
java.lang.Boolean object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf80020cc
12 1 boolean Boolean.value true
13 3 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
class java.lang.Byte
java.lang.Byte object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf8002220
12 1 byte Byte.value 1
13 3 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
5. 引用类型
5.1 基本类型数组
int[] intArray=new int[100];
class [I
[I object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800016d
12 4 (array length) 100
12 4 (alignment/padding gap)
16 400 int [I.<elements> N/A
Instance size: 416 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
数组比对象多了4字节的数组长度
5.2 引用类型数组
Integer[] integerArray=new Integer[100];
[Ljava.lang.Integer; object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf8006250
12 4 (array length) 100
12 4 (alignment/padding gap)
16 400 java.lang.Integer Integer;.<elements> N/A
Instance size: 416 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
包装类型的数组通常比原始类型的数组占用更大的空间。上面两个数组空间相同,因为包装类型数组中的元素都为空。
5.3 普通对象的内存布局
me.ffulauh.javalang.object.D object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf8010777
12 4 int D.pint 0
16 4 java.lang.Integer D.xint null
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
5.4 有继承关系的对象内存布局
从下面的内存布局可以看出,先排列父类的字段
me.ffulauh.javalang.object.C object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf8010835
12 4 int A.iInt 0
16 4 me.ffulauh.javalang.object.A A.a null
20 4 int B.iInt 0
24 8 long B.lLong 0
32 4 float B.fFloat 0.0
36 1 byte B.bByte 0
37 3 (alignment/padding gap)
40 4 me.ffulauh.javalang.object.B B.b null
44 4 int C.iInt 0
48 8 long C.lLong 0
56 4 float C.fFloat 0.0
60 1 byte C.bByte 0
61 3 (alignment/padding gap)
64 4 me.ffulauh.javalang.object.C C.c null
68 4 (object alignment gap)
Instance size: 72 bytes
Space losses: 6 bytes internal + 4 bytes external = 10 bytes total
6. 示例代码
package me.ffulauh.javalang.object;
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
public class ObjectSizeTest {
public static void main(String[] args) {
long size=ObjectSizeCalculator.getObjectSize(Integer.parseInt("1"));
size= VM.current().sizeOf(Integer.parseInt("1"));
Long xLong=1L;
printLayout(xLong);
Double xDouble=1.0;
printLayout(xDouble);
Integer xInt=1;
printLayout(xInt);
Float xFloat=1f;
printLayout(xFloat);
Short xShort=1;
printLayout(xShort);
Character xChar='a';
printLayout(xChar);
Boolean xBool=true;
printLayout(xBool);
Byte xByte=1;
printLayout(xByte);
//数组
int[] intArray=new int[100];
printLayout(intArray);
Integer[] integerArray=new Integer[100];
System.out.println(ClassLayout.parseInstance(integerArray).toPrintable());
//对象
D a=new D();
System.out.println(ClassLayout.parseInstance(a).toPrintable());
//对象继承
C c=new C();
System.out.println(ClassLayout.parseInstance(c).toPrintable());
}
public static void printLayout(Object obj){
System.out.println(obj.getClass());
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
package me.ffulauh.javalang.object;
public class A {
int iInt;
A a;
}
package me.ffulauh.javalang.object;
public class B extends A{
long lLong;
int iInt;
float fFloat;
byte bByte;
B b;
}
package me.ffulauh.javalang.object;
public class C extends B{
long lLong;
int iInt;
float fFloat;
byte bByte;
C c;
}
package me.ffulauh.javalang.object;
public class D {
int pint;
Integer xint;
}