
前言
在家工作的第N周。
我不知道公司是否还在...
靠近主题,回到正文“对象标题”
对于学习Java,对象标头可以是基本知识点之一一.
假定存在通向Java语言的门,则对象标头的状态为“进入门时的知识”。没有技术要点,但是您需要知道。
“同步锁定标志存储在哪里?”,“对象多大了?对象的世代年龄在哪里”等。当您第一次学习Java时,这些问题是不可避免的。这些与对象标题密切相关。
对于不清楚“对象标头”的读者,您可以继续阅读,本文将向您大致介绍“对象”中安装了什么。
简介
首先提出基本概念,后来作者提出了具体做法。
对象标头是文字转换,有点钝。根据作者的说法,它可以被称为“对象名片”,并且可以更加吸引人。它主要包含对象的基本信息,例如:
身份哈希码是指由jvm计算而无需重写的哈希码。
整个对象标头由两部分组成,即:klass指针和Mark Word。
当然,在介绍这两件事之前,我需要在这里强调:本文默认情况下基于jdk1.8和64位环境,这是一种标准配置。
黄铜指针
黄铜指针通常占用32位或4个字节。如果有足够的理由关闭默认的指针压缩,即启动参数添加-XX:-UseCompressedOops,则它占用64位。
但是这里还有更多细节:根据计算,在堆大小超过32GB之后,即使未打开指针压缩也不会报告错误,但是指针压缩将失败。
但是作者没有进行实际测试,原因是...

堆大小必须为32GB +内存,并且一些内存为非堆和OS保留。这种存储器机器不适用于作者的三线小型工厂。但是,作者找到了其他人的测试文章,并将其放在本文的底部。有兴趣的人可以看看。
klass指针的存储内容是一个指向其类元数据信息的指针。 JVM使用此指针来确定此对象是类的哪个实例。
什么意思?如果您引用了Person实例,则找到依赖于该实例的元数据,如图所示:

标记单词
关于标记词是Java程序员的重要知识,是一开始的图片:

表中的“场景”也可以理解为“状态”。一个对象一次处于一种状态,但是它可以在状态之间切换。
这是您使用的对象,它在当前表中,处于“一行”状态。
Mark Word位于64位虚拟机中,这意味着它占用64位大小或8个字节的空间。
具体内容包括:
如果您看cms_free,该字体有点奇怪,是的,它最初被误涂为未使用,后来发现默认情况下“指针压缩”处于打开状态,那么该位应该是cms_free。
cms_free与名称中的cms收集器有关,因为cms算法是标记清除收集器,所以内存碎片问题是在空闲列表中维护无法访问的对象。我猜这应该是标记对象是否在空闲列表中。
作者推测了有关cms_free的结论。您无需相信。如果您认为作者的说法不正确,可以告诉我。
如果您认为作者的说法是错误的,但是您无法提供任何证据,则不必太认真,毕竟jdk14 cms已被删除。
初学者对这些事情感到很满意,因此他们可以开始了解解锁行下的内容。
在阅读了这些内容之后,阅读了作者上面所说的“标记词对于Java程序员来说是更重要的知识”之后,相信您也知道原因。这部分与程序有很多关系,例如:
为什么要升级到老一代的年龄设置(XX:MaxTenuringThreshold)不能超过15岁?

由于使用了四个位空间,因此最大值为1111(二进制),即15,因此没有地方可以存储更多空间。
为什么您的同步锁对象没有“传奇”偏向锁优化?
因为在实例化对象后未计算哈希码,所以通过调用计算哈希码并将其放在标记字中。
您已经调用了hashcode方法(或隐式调用:存储在hashset中,映射的键,称为默认的未重写toString方法等)来占据“坑”,并且更喜欢锁定所需的没有存储线程ID的位置,因此它自然是轻量级的锁。
(或者您只是在测试时就忘记添加-XX:BiasedLockingStartupDelay = 0)
看来设计有点不合理,但还是很合理的。基础设计是如此朴实无趣。
本文的重点是“对象标头”,因此我不会重点关注锁。正如我之前所说,“哈希码被调用并同步,并且被发现是轻量级的锁。”实际上,有很多情况,
例如:即使存在偏向锁,在同步块中调用的哈希码计算方法也将被撤销,并将扩展为重量级锁。如果有缘分,将来您可能会看到作者单独描述锁的文章。
实践
实践带来了真正的知识。如果您想做得好,则必须首先完善工具。只需使用jol工具。 Openjdk提供了用于分析对象的大小和布局的工具。
本文使用最简单的方法将带有maven的项目引入进行测试。您还可以选择命令行方法,以上jol链接中都介绍了这两种方法。
在介绍了jol之后,我们开始打印对象布局以进行尝试。
数组对象布局
publicstaticvoidmain(String [] args){
//声明一个长度为3306的数组
int [] intArr = newint [3306];
//使用jol的ClassLayout工具分析对象布局
系统。 out.println(ClassLayout.parseInstance(intArr).toPrintable); }

打印:--------------------------------------------- --------- [我反对内部人员:
偏移尺寸类型的离子值
04(objectheader)01000000(0000000000)(1)
44(objectheader)00000000(0000000000)(0)
84(objectheader)6d 0100f8(0011111000)(-134217363)
124(objectheader)ea 0c 0000(0000000000)(3306)
1613224int [I。不适用
实例大小:13240bytes
空间损失:内部0字节+外部0字节=总计0字节
如果您是第一次查看jol印刷的布局图,则可以直接查看作者标记的以下图片:

对象标头的三个部分分别确认上述的klass指针和Mark Word以及数组的唯一长度属性。
右侧使用三个基数来显示“每行”的值,与上述内容相同:
尚未调用原始哈希码方法(包括System.identityHashCode方法),则哈希码位置为0.
从图中可以得出结论,对象刚刚被实例化时非常“干净”。乍看之下,有两行0,但是只有一个1非常突然。
实际上,它是001,它是上面提到的偏置锁定标志+锁定标志。所有锁的状态如下:
偏置锁定标志锁定标志的状态
01

无锁
1
01
部分锁定
-
00
轻巧的锁
-
10
重量级锁
-
11
GC标签
这一次很清楚。尽管有1,但实际上是未锁定的。
返回到布局图,因为它是一个数组对象,所以数组的长度存储在第四行中,并且没有非数组对象。
对象大小的计算也非常准确,即:13224(一个int是四个字节乘以3306) + 16 = 13240字节。
自己练习的提示
看到对象布局朴实的设计,您也可以尝试一下。
作者还附上一些提醒:
如果您不注意这些要点,则打印后可能会茫然不知所措,不知道哪些位对应于哪些字段,甚至结果与预期的也不一样。
最后
实际上,有许多关于对象结构的细节值得您进一步阅读。本文仅简要介绍“对象标头”的一小部分。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/shumachanpin/article-334643-1.html
萌死我啦