1.HotSpot中,对象在内存中分为3块区域:
补充说明KlassPointer : 例如我们执行main方法,类加载器会将主类加载到JVM,经历 加载-》验证-》准备-》解析-》初始化的过程,其中加载这一步,会去生成 Class对象作为方法区中,这个类的各种数据的访问入口。(类元信息放方法区,class是堆中的)而jvm实际是通过方法区的klass得到这个类的信息。
32位:
64位:
2.通过一个demo了解这三块区域
引入依赖
org.openjdk.jol
jol-core
0.9
public class JOLSample {
public static void main(String[] args) {
ClassLayout layout = ClassLayout.parseInstance(new Object());
System.out.println(layout.toPrintable());
System.out.println();
ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});
System.out.println(layout1.toPrintable());
System.out.println();
ClassLayout layout2 = ClassLayout.parseInstance(new A());
System.out.println(layout2.toPrintable());
}
// -XX:+UseCompressedOops 默认开启的压缩所有指针
// -XX:+UseCompressedClassPointers 默认开启的压缩对象头里的类型指针Klass Pointer
// Oops : Ordinary Object Pointers
public static class A {
//8byte mark word
//4byte Klass Pointer 如果关闭压缩-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,则占用8byte
int id; //4byte
String name; //4byte 如果关闭压缩-XX:-UseCompressedOops,则占用8byte
byte b; //1byte
Object o; //4byte 如果关闭压缩-XX:-UseCompressedOops,则占用8byte
}
}
结果说明
OFFSET:偏移量 (不关注)
SIZE:占用的字节
TYPE:类型
DESCRIPTION:前半部分为十六进制,后半部分为二进制(括号部分)
window和linux默认为小端模式(更适合计算机底层原理,即从低位读取)
00001010 00001011 00001111 10000000 //工具打印出来的
10000000 00001111 00001011 00001010 //实际上计算机中为反过来,此时锁为重量级锁
Instance size: 总共占用的字节数
MarkWord用红框表示,klass指针用橙框,数组长度用灰框。
实例数据用黄框,对齐填充用淡蓝框
成员变量中的类大多都是占用4bit(指针压缩后4bit,未压缩8bit)
结果一:(没有成员变量的)
红色部分描述不严谨,实际为对象头的MarkWord部分
结果二:(数组)
int [I.element 部分为数组中的数据,demo中为空,所以占0字节,索引每多1个,多加4字节(加多少具体看类型,int为4)
结果三:(创建的普通类)
实例数据中, int占4byte;String占4byte(字符串是存储在常量池,所以此处占用的是name的引用指向池的‘地址’); byte和bool占1byte;long占8byte…
3.通过一个demo了解锁标志位
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o){
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
结果一:
00000001 00000000 00000000 00000000 (无锁状态)
结果二:
01101000 11110001 11110101 00000000(轻量级锁)
对应最上面的锁标志位可知,结果一为【无锁状态】,结果二为【轻量级锁】