JVM调优笔记(四)Java对象的内存布局

Java对象内存布局

Java对象内存布局

位置存储内容所占大小
对象头8字节的标志位,存储分代年龄,hashcode(获取才会存储)等标志
8字节的classpointer,指向类的元数据地址,方法区
如果是数组对象,4字节存储数组的大小长度,如果不是数组对象,则不包含
8字节(64位系统)
+8字节
+4字节
实例数据存储着对象包含的所有成员变量,大小根据不同的数据类型空间不同
boolean和byte是1字节
short和char是2字节
int和float是4字节
long和double是8字节
引用类型是8字节
填充数据将对象的所占空间填充为8字节的整数倍,以适配CPU的读取,是空间换时间的思想

目的

了解Java的对象布局,可以在相关高并发场景下,计算出会产生多大的内存,用来调整JVM大小

工具JOL Demo

maven依赖
<dependency>
  <groupId>org.openjdk.jol</groupId>
  <artifactId>jol-core</artifactId>
  <version>RELEASE</version>
</dependency>
demo代码
package com.bayitalk.clazz;
import org.openjdk.jol.info.ClassLayout;
/**
* 测试对象的布局
*/
public class TClass {
    private final static int a = 20;
    private static int b = 129;
    private int c = 12;
  	private int d = 10;
    private static String comment = "This is Test class";
    public String getComment(){
        return comment;
    }
    public static void main(String[] args) {
        System.out.println(ClassLayout.parseInstance(new TClass()).toPrintable());
    }
}
输出结果
com.bayitalk.clazz.TClass object internals:
OFF  SZ   TYPE DESCRIPTION               VALUE
  0   8        (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4        (object header: class)    0xf800c105
 12   4    int TClass.c                  12
 16   4    int TClass.d                  10
 20   4        (object alignment gap)    
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
解析
  1. 8个字节的标志位,并且是大端存储
  2. 标志位中并没有hashcode的值,是因为hashcode只有调用了hashcode相关的方法才会存储进标识位
  3. class pointer是4个字节,因为存在指针压缩,为了减少空间和减少GC的频次
  4. 实例对象只存储了成员变量
  5. 有4个字节的填充字段,用来填充成8字节的整数倍
备注

小端存储:便于数据类型转换,例如long转int可以直接舍弃

大端存储:便于符号判断,最低位是符号位

指针压缩超过32G会失效。32位的处理器,内存大概4G

ClassPointer

classpointer存储的是指向类元数据(方法区)的地址,因此Java采用的是直接指针访问对象.

句柄池访问对象

句柄池访问对象

直接指针指向

直接指针访问对象

句柄池和直接引用的区别
访问方式定义优劣势
句柄池访问对象句柄池访问,会再堆中单独开辟一个空间,存储对象实例数据和类元类型数据的指针优势:reference存储的是句柄的地址,在对象实例移动的时候,不需要维护reference,只需要修改句柄池就好。
劣势:需要额外的存储空间,增加了一次指针跳转的开销
直接指针指向在对象的实例数据中直接存储类元类型数据的指针优势:减少了一次指针定位的开销
劣势:在GC等移动复制对象的时候,需要维护相应的reference

指针压缩

  • 为了保证CPU缓存,存储更多的对象指针,将8字节压缩成4字节
  • 减少GC发生的频次,占更少的资源
  • 关闭指针压缩 : -XX:-UseCompressedOops
  • 64位系统,4G内存默认开启指针压缩,超过32G之后,指针压缩失效,32位系统的CPU 最大支持2^32 = 4G ,如果是64位系统,最大支持 2^64, 但是对其填充是按照8字节进行填充,指针压缩可以理解为在32位系统在64位上面使用,因为32位系统的CPU寻址空间最大支持4G,对其进行8字节填充 = 32G,这就是内存超过32G指针压缩失效的原因。

对齐填充

  • 对齐填充,是为了提高CPU的访问效率

  • 因此对对象的实例数据进行更好的排序,有助于对齐填充产生的内存碎片

  • 对象的实例数据顺序,并不一定是编码顺序,这个和Hotspot的FieldsAllocationStyle取值有关系。

FieldsAllocationStyle取值
取值含义备注
0基本数据类型的原始引用 > 填充字段 > 引用类型填充的字节是为了对齐8字节填充的空白
1引用类型 > 基本类型 > 填充字段默认1
2父类的引用和子类的引用放在一块,父类策略采用0,子类策略采用1,但是父子类的数据是有隔离的如果一个项目的继承关系特别多,采用策略2,可以提高GC的销量,父子类的引用在一起,方便查找
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值