java -XX:+PrintCommandLineFlags 打印可以看出
-XX:InitialHeapSize=29844928 -XX:MaxHeapSize=477518848 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
默认是开启的对象指针压缩和 类指针压缩,用来提高内存的利用率,变量槽 长度 在没开启对象指针压缩 时, Object o = new Object() 变量o 占用一个变量槽。
64位操作系统,默认是开启对象指针要锁 compressedOops 对象的实例 对象头 mark word 占用 8个字节,class 类型指针占用4字节 填充数据占用 4 字节 16 字节;
Object o = new Object(); jvm 对象的起始地址 必须是 8字节的整数倍
开启压缩: mark word[8 字节] + classPointer[4字节] + 填充数据 [4字节] = 16 字节
关闭压缩:mark word[8 字节] + classPointer[8字节] = 16 字节
o 变量 占用一个变量槽 +UseCompressedOops 占用 4字节,
-UseCompressedOops 占用 8 字节
UseCompressedClassPointers requires UseCompressedOops 所以至少 占用 20 字节
不管是否开启类型指针压缩 对象实例都占用 16 字节【jvm 规范规定对象的起始地址必须是8字节的整数倍】,关键就在于是否开启了 对象指针压缩 ,
开启了类型指针压缩,默认就开启了 对象指针压缩,类型指针压缩前置条件就是开启对象指针压缩
-XX:+UseCompressedClassPointers 则必须 -XX:+UseCompressedOops
说明:局部变量表(Local Variables Table)是一组变量值的存储空间,用于存放方法参数和方法内部定义 的局部变量。在Java程序被编译为Class文件时,就在方法的Code属性的max_locals数据项中确定了该方 法所需分配的局部变量表的最大容量。 局部变量表的容量以变量槽(Variable Slot)为最小单位,《Java虚拟机规范》中并没有明确指出 一个变量槽应占用的内存空间大小,只是很有导向性地说到每个变量槽都应该能存放一个boolean、 byte、char、short、int、float、reference或returnAddress类型的数据,这8种数据类型,都可以使用32位 或更小的物理内存来存储,但这种描述与明确指出“每个变量槽应占用32位长度的内存空间”是有本质 差别的,它允许变量槽的长度可以随着处理器、操作系统或虚拟机实现的不同而发生变化,保证了即 使在64位虚拟机中使用了64位的物理内存空间去实现一个变量槽,虚拟机仍要使用对齐和补白的手段 让变量槽在外观上看起来与32位虚拟机中的一致。对于64位的数据类型,Java虚拟机会以高位对齐的方式为其分配两个连续的变量槽空间。Java语言 中明确的64位的数据类型只有long和double两种。这里把long和double数据类型分割存储的做法与“long 和double的非原子性协定”中允许把一次long和double数据类型读写分割为两次32位读写的做法有些类似
mark word 对象头 {哈希码,偏向线程id,偏向时间戳,分代年龄[4bit位],锁状态,锁标志位}
类型指针 [标识 实例对象是属于哪个类型的实例]
字段填充 [jvm 中要求对象的起始地址是 8字节的整数倍]
数组长度[数组]
开启压缩: mark word[8 字节] + classPointer[4字节] + 填充数据 [4字节] = 16 字节
关闭压缩:mark word[8 字节] + classPointer[8字节] = 16 字节
---------------------------------- 更新-----------------------------------
分配内存:(jvm规范中对象的大小必须是8字节的整数倍) 对象在堆中的结构: (1)对象头 mark word [ hash码,GC分代年龄,锁状态,锁标志位,偏向标识,偏向时间戳 ] / 类型指针 / [数组长度] (2)对齐填充 Object o = new Object(); 在堆中的大小 16 byte [开启指针压缩] 对象头 mark word 占用 8个字节,class 类型指针占用4字节 填充数据占用 4 字节 16 字节; -XX:+UseCompressedClassPointers -XX:+UseCompressedOops 对象头(12 / 16) 对齐填充(4 / 0 ) 变量(o)一个变量槽 (4 / 8) 开启压缩: mark word[8 字节] + classPointer[4字节] + 填充数据 [4字节] = 16 字节 + 4字节 关闭压缩: mark word[8 字节] + classPointer[8字节] = 16 字节 + 8字节 o 变量 占用一个变量槽 +UseCompressedOops 占用 4字节, -UseCompressedOops 占用 8 字节 UseCompressedClassPointers requires UseCompressedOops 所以至少 占用 20 字节 分配内存的策略: (1)指针碰撞 a. 并发冲突的解决:CAS + 重试机制 (2)空闲列表 b. 本地线程缓冲 Thread local allocate buffer TLAB技术