上海工商查询网官方网站,西凤酒网站建设,wordpress mxl-rpc服务,网易网站建设文章目录 版本及工具介绍Java 对象结构对象头mark word 标记字mark word 标记字解析Lock Record class point 类元数据指针 实例数据对齐填充为什么需要对齐填充 常见 Java 数据类型对象分析ArrayListLongStringByteBoolean 其它指针压缩前置知识#xff1a;32位操作系统为什么… 文章目录 版本及工具介绍Java 对象结构对象头mark word 标记字mark word 标记字解析Lock Record class point 类元数据指针 实例数据对齐填充为什么需要对齐填充 常见 Java 数据类型对象分析ArrayListLongStringByteBoolean 其它指针压缩前置知识32位操作系统为什么最多支持 4G 内存从32位操作系统到64位操作系统指针压缩使用4字节指针的同时获得更大的内存如何开启指针压缩实现原理 思考mark word 数据字段为什么是不固定动态变化的mark word 是字段动态变化的当获取锁时 hash code 等字段被存储在哪 个人简介 版本及工具介绍
JDK版本JDK 8Java 对象分析 Maven 插件 dependencygroupIdorg.openjdk.jol/groupIdartifactIdjol-core/artifactIdversion0.17/version/dependencyJava 对象结构
一个 Java 对象由三部分组成对象头、实例数据、对齐数据其中对象头分为 mark word 标记字和 class point 类元数据指针。 jol-core 是 Java Object LayoutJOL库的一部分它是一个用于分析Java对象内存布局的工具。JOL 允许我们深入了解Java对象的内部结构包括字段的偏移量、大小和布局以及对象头的信息等。这对于性能优化和调试非常有用特别是当我们需要了解对象在内存中的布局时。如何使用 jol-core 打印Java对象信息
public class Test {static final A MUTEX new A();public static void main(String[] args) {// 打印 JVM 信息System.out.println(VM.current().details());// hashCode 懒加载调用 hashCode() 方法时生成存储在对象头System.out.println(MUTEX.hashCode());System.out.println(ClassLayout.parseInstance(MUTEX).toPrintable());synchronized (MUTEX) {System.out.println(ClassLayout.parseInstance(MUTEX).toPrintable());}System.out.println(ClassLayout.parseInstance(MUTEX).toPrintable());}
}class A {int a 2;
}// 输出
# VM mode: 64 bits
# Compressed references (oops): 3-bit shift
# Compressed class pointers: 3-bit shift
# Object alignment: 8 bytes
# ref, bool, byte, char, shrt, int, flt, lng, dbl
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
# Array base offsets: 16, 16, 16, 16, 16, 16, 16, 16, 161407343478 // 对象 hashCodeconcurrency.A object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x00000053e25b7601 (hash: 0x53e25b76; age: 0)8 4 (object header: class) 0xf800c14312 4 int A.a 2
Instance size: 16 bytes
Space losses: 0 bytes internal 0 bytes external 0 bytes total// 64位JVM mark word 占用8字节
// 64位JVM class point 元数据指针占用4字节正常应该占用8字节这里开启了指针压缩
// 实例数据 int字段占用4字节
// 共计 16 字节 默认8字节对齐不需要补齐concurrency.A object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x00000096d75ff7e8 (thin lock: 0x00000096d75ff7e8)8 4 (object header: class) 0xf800c14312 4 int A.a 2
Instance size: 16 bytes
Space losses: 0 bytes internal 0 bytes external 0 bytes totalconcurrency.A object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x00000053e25b7601 (hash: 0x53e25b76; age: 0)8 4 (object header: class) 0xf800c14312 4 int A.a 2
Instance size: 16 bytes
Space losses: 0 bytes internal 0 bytes external 0 bytes total对象头
对象头由 mark word 标记字和 class point 类元数据指针两部分组成。
mark word 标记字
mark word 记录了 Java 对象运行时的数据信息如持有的锁、是否是偏向锁、锁持有线程、hashcode、分代年龄等等32位JVM中占用4个字节64位JVM中占用8个字节具体字段如下所示 mark word 标记字解析
补充知识
大端存储(Big-Endian)数据的高字节存储在低地址中数据的低字节存储在高地址中
小端存储(Little-Endian)数据的高字节存储在高地址中数据的低字节存储在低地址中// 上文示例 Mark word 分析 JVM 64位
0x00000053e25b7601 (hash: 0x53e25b76; age: 0)十六进制数: 0x00000053e25b7601
二进制数: 0000 0000 0000 0000 0000 0000 0101 00111110 0010 0101 1011 0111 0110 0000 0001锁标记 01 无锁
分代年龄0000 age:0
hashCode: 101 0011 1110 0010 0101 1011 0111 0110 hash: 0x53e25b76 十进制14073434780x00000096d75ff7e8 (thin lock: 0x00000096d75ff7e8)十六进制数: 0x00000096d75ff7e8
二进制数: 0000 0000 0000 0000 0000 0000 1001 01101101 0111 0101 1111 1111 0111 1110 1000锁标记 00 轻量级锁
指向线程堆栈Lock Record指针
0000 0000 0000 0000 0000 0000 1001 0110 1101 0111 0101 1111 1111 0111 1110 10Lock Record
lock record 保存对象 mark word 的原始值还包含识别哪个对象被锁的所必需的元数据。
class point 类元数据指针
class point 类元数据指针指向方法区的instanceKlass实例虚拟机根据该指针确认对象是哪个类的实例32位JVM中占用4个字节64位JVM中占用8个字节或4个字节指针压缩。
实例数据
存储对象的字段信息。包括继承的字段
对齐填充
Java 对象的大小默认8字节对齐当大小不为8的倍数时需要进行对齐填充如14字节需要填充为16字节。
为什么需要对齐填充
对齐填充是一种以空间换时间的方案可以提高内存的访问效率本质是为了更加高效的利用缓存行。
示例
CPU缓存行Cache Line是计算机处理器缓存的最小存储单位一般来说32 位系统一般为 4字节、64位系统一般为 8字节。指针压缩技术也依赖 Java 对象字节对齐。
常见 Java 数据类型对象分析
ArrayList
java.util.ArrayList object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)8 4 (object header: class) 0xf8002f3912 4 int AbstractList.modCount 316 4 int ArrayList.size 320 4 java.lang.Object[] ArrayList.elementData [(object), (object), (object), null, null, null, null, null, null, null, null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal 0 bytes external 0 bytes totalLong
java.lang.Long object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)8 4 (object header: class) 0xf80022c012 4 (alignment/padding gap) 16 8 long Long.value 1
Instance size: 24 bytes
Space losses: 4 bytes internal 0 bytes external 4 bytes totalString
java.lang.String object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)8 4 (object header: class) 0xf80002da12 4 char[] String.value [S, t, r, i, n, g]16 4 int String.hash 020 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal 4 bytes external 4 bytes totalByte
java.lang.Byte object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)8 4 (object header: class) 0xf80021eb12 1 byte Byte.value 113 3 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal 3 bytes external 3 bytes totalBoolean
java.lang.Boolean object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)8 4 (object header: class) 0xf800209712 1 boolean Boolean.value true13 3 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal 3 bytes external 3 bytes total其它
指针压缩
前置知识32位操作系统为什么最多支持 4G 内存
先看一张8字节的内存
如果需要寻址上面的所有格子那么我们需要 2^6 次方个地址即 6位操作系统。相同的算法我们计算32位的操作系统:
2^32 bit 2^29 byte 2^19 KB 2^9 MB 2^-1 GB 0.5 GB实际值为0.5G但是为什么说32位 CPU 最多支持 4G 内存呢实际上CPU会把 8 bit1Byte当作一组即最小的读取单元为 1 Byte, 因此 2^32 * 1 Byte 4G// 实际上能够使用的内存大小由两方面决定硬件和操作系统操作系统指的是虚拟地址层面而硬件指的是地址总线。
// 其它参考https://www.zhihu.com/question/22594254/answer/42967413从32位操作系统到64位操作系统
从上面我们知道32操作系统最多使用的内存为4G随着我们开发的程序越来越复杂32位操作系统已经不能满足我们的内存需求我们进入了64操作系统的时代我们可以使用的内存达到 4G * 2^32 但指针长度也达到了8个字节过长的指针带来了新的问题
1、增加了GC开销64位对象引用需要占用更多的堆空间留给其他数据的空间将会减少从而加快了GC的发生更频繁的进行GC。
2、降低缓存命中率64位对象引用增大了内存能缓存的oop将会更少从而降低了缓存的效率。指针压缩使用4字节指针的同时获得更大的内存
如何开启指针压缩
-XX:UseCompressedOops // 对象指针压缩
-XX:UseCompressedClassPointers // 类元数据指针压缩// 如上示例中已开启
# Compressed references (oops): 3-bit shift
# Compressed class pointers: 3-bit shift// 64 JVM class point 占用4个字节
concurrency.A object internals:
OFF SZ TYPE DESCRIPTION VALUE0 8 (object header: mark) 0x00000053e25b7601 (hash: 0x53e25b76; age: 0)8 4 (object header: class) 0xf800c14312 4 int A.a 2
Instance size: 16 bytes
Space losses: 0 bytes internal 0 bytes external 0 bytes total实现原理
// JVM 中 java对象默认8字节对齐 最大堆内存 32 GB(4G * 2^3)超过 32 GB 指针压缩将失效
-XX:ObjectAlignmentInBytes8字节对齐的情况下地址的后三位总是为08 100016 1000024 1100032 10000040 10100048 11000056 11100064 100000072 1001000因此在Java对象中存储时通过右移三位将3个0抹去从内存中获取值时再通过将Java对象中的地址左移3位补0从而实现使用4个字节获得 2^32 * 2^3 个内存地址一个内存地址指向 1Byte 则总计32G内存这也是为什么我们经常看到一些文章中说Java堆内存不要超过32G的原因因为4字节指针8字节对齐无法表示超过32内存会关闭指针压缩除非调整对齐字节数来扩大可访问的内存空间。设置为16字节对齐最大堆内存 64 GB(4G * 2^4)超过 64 GB 指针压缩将失效16 1000032 10000048 11000064 1000000思考
mark word 数据字段为什么是不固定动态变化的
实现不增加对象的内存占用的情况下支持对象锁并发和锁优化。
mark word 是字段动态变化的当获取锁时 hash code 等字段被存储在哪
HotSpot VM 若为偏向锁则未获取 hash code若已获取 hash code 则不会获取偏向锁而是直接获取轻量级锁若为偏向级锁此时获取 hash code 则会膨胀为重量级锁轻量级锁时 hash code 存放在 Lock Record 中重量级锁时 hash code 存放在 ObjectMonitor 对象上。注意这里讨论的hash code都只针对identity hash code。用户自定义的hashCode()方法生成的 hash code 不会放在对象头。Identity hash code是未被覆写的 java.lang.Object.hashCode() 或者 java.lang.System.identityHashCode(Object) 所返回的值。参考大R回答https://www.zhihu.com/question/52116998/answer/133400077
个人简介 你好我是 Lorin 洛林一位 Java 后端技术开发者座右铭Technology has the power to make the world a better place. 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。 作为一个 Java 后端技术爱好者我不仅热衷于探索语言的新特性和技术的深度还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。 在我的博客上你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法以帮助你更好地掌握Java编程。 我鼓励互动和建立社区因此请留下你的问题、建议或主题请求让我知道你感兴趣的内容。此外我将分享最新的互联网和技术资讯以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进一起探讨技术世界的无限可能性。 保持关注我的博客让我们共同追求技术卓越。