【随笔】CLR:向头对象(Object Header)迈进一大步!!!
前言
在我之前一篇随笔里(戳我),我们知道,一个引用类型的对象,包含了2个额外的开销,一个是头对象(object header),一个是MT。我们接下来看看头对象到底有多神秘。。。
Object Header中的布局
头对象共32位,每一位都有不同的用途
- 当27位为1时:则0~26位存储的都是和thin lock相关的信息,其中还细分了3个范围用来存放不同的信息
- 当27位为1时&26位为1时:则0~25位存储的都是对象的hash值
- 当27位为1时&26位为0时:则0~25位存储的都是sync block index,指向的是sync block table
相关资料可参见:
https://mycodingplace.wordpress.com/2018/01/10/object-header-get-complicated/
https://www.markopapic.com/csharp-under-the-hood-locking/
https://github.com/dotnet/coreclr/blob/master/Documentation/botr/threading.md
Object Header常用的4个用途
1。线程同步
lock的时候会用到,(戳我),这里不再演示,不过下面我想用lldb来一探究竟。
先来看下我们的代码:
然后我们用lldb, attach进去看看
试了下,这个syncblk命令不可用,我们换一个
发现还真有2处地方,拥有锁,我们通过地址,继续剖析:
图中,第二个锁,就忽略了,应该是console程序用的,和本案例无关,我们只看第一把锁,这已经证明了当前执行线程中的内存中,存在一把锁,而且是thinlock,
被锁的对象,则是Person对象p1。好奇的你应该会问:thinlock又是什么鬼。我找了一些资料
https://devblogs.microsoft.com/premier-developer/managed-object-internals-part-2-object-header-layout-and-the-cost-of-locking/
https://mycodingplace.wordpress.com/2018/01/10/object-header-get-complicated/
2。Hash值存储
上代码
程序跑起来,然后找到person对象:
当我们调用了对象的gethashcode方法之后,clr会把这个对象的hash值,存储在对象头中:
我们把对象头中的前8位拿出来,0x0e97b065,然后转成2进制,得到1110100101111011000001100101,我们逐位代入到表格中:
由表格中可以得出,当前同步信息存储的这个值,符合BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX:1 & BIT_SBLK_IS_HASHCODE:1
表示0~25位之间,存放的是该对象的hash值。我们把值取出来则为10100101111011000001100101,然后转化成10进制则为:43495525
刚好与我们打印出来的内容一致。
所以说,对象的头信息中还有存放Hash值的用途。
3。用于GC回收时的标记阶段