zoukankan      html  css  js  c++  java
  • 揭示同步块索引(下):总结 转载

    揭示同步块索引(下):总结

    同步块的三个作用

    1  GC启动时候用来进行垃圾回收算法的时候会用到同步块的一个位,作为标志

    2  hashcode

    3  lock

    前面,我用两篇文章详细的讨论了同步块索引在lock和GetHashCode所起的作用。不过两篇文章是分开来讨论的。那可能有人会问,如果我有一个object,它既作为lock的lockHelper对象,也要调用它的GetHashCode方法该怎么办,难道这个同步块索引还可以承担这两个任务么。同步块索引是可以承担这两个任务,但是里面却隐藏着更大的秘密,我们先来看看与同步块索引相关的结构:

    大致就是这样的一个结构,一个对象的ObjectHeader中的SyncBlockIndex指向一个Sync Block Entry Table中的一项,这里用虚线表示,是说明这里不是使用指针直接的指向,而是一个索引,这样有个什么好处呢,就是CLR可以随便把这个Table放在哪里,也可以按需增大这个Table的容量,反正我这里使用的是索引而不是指针,是间接的指向。这个Table里的每一项都是一个SyncTableEntry,这个SyncTableEntry有两个字段,第一个字段是一个SyncBlock的指针,指向一个SyncBlock对象。还有一个字段是一个Object指针,有了这个指针CLR就可以跟踪这个SyncBlock是哪个对象的,而且SyncTableEntry和SyncBlock不是放在GC管理的内存中,所以可以根据这个Object*来跟踪对应的对象的实例,当对象死亡后,可以回收对应的SyncBlock和SyncTableEntry,不过这个Object的指针是一个弱引用(弱引用的作用是,如果没有任何强引用引用该对象,则该对象可以被认为是垃圾,允许被垃圾收集)。

    不过要注意的是,上面这种结构并不是一个对象“与生俱来”的,也就是说对象刚初始化的时候并不如此。当一个对象刚初始化的时候,在ObjectHeader中,SyncBlockIndex字段是为0的,这个在上一篇文章中的Visual Studio + SOS的实验中我们已经见到过。而如果调用对象的GetHashCode方法,则对象的ObjectHeader中的SyncBlockIndex字段的低26位则用来存储该对象的HashCode,而高6位作为一个标识,表示现在SyncBlockIndex作为存储HashCode之用,具体做法就是将这个SyncBlockIndex与BIT_SBLK_IS_HASHCODE (#define BIT_SBLK_IS_HASHCODE 0x04000000)作或运算,判别的时候作一下与运算。这个在上一篇文章中也介绍了。而如果调用对象的GetHashCode方法之后,继续将该对象作为lock的对象使用呢?这个时候SyncBlockIndex的低26位会摇身一变,变成一个索引,而且还与BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX (#define BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX 0x08000000)作一下或运算,表示这个SyncBlockIndex现在啊既有存储HashCode之功用,又要作为lock的对象。

    那既然这低26位变成了索引,那原来的HashCode跑到哪里去了呢?这个就要一探SyncBlock的结构了:

    SyncBlock结构

    我们看到最后一个字段,这个字段就是如果SyncBlockIndex还做其他用途是,CLR会将计算所得的hashcode放到这里。而如果对象只作lock对象使用,而没有调用GetHashCode方法,则这个字段为0。根据调用的顺序,这个m_dwHashCode的设置有两种方式:

    1、已经调用了GetHashCode方法,然后作lock之用,那这里的m_dwHashCode就是之前存储在SyncBlockIndex中的低26位。

    2、先作lock之用,然后调用GetHashCode,那m_dwHashCode就是当时新生成的HashCode,然后放在这里的。

    从图中我们还有ADIndex这么一个字段,这个字段是表示当前这个对象属于哪个AppDomain,实际上这个字段也可以在SyncBlockIndex里设置,但是如果SyncBlockIndex要担负别的责任,比如该对象作为lock对象时,ADIndex就在SyncBlock里这个字段设置了。关于为什么需要这个ADIndex我现在还没弄清楚,等我弄明白了,再来更新这篇文章。

    SyncBlock的第一个字段是AwareLock,实际上这个东西和我第一篇文章中提到的CRITICAL_SECTION结构是一样的,具体细节可以参见“揭示同步索引块(上)-从lock开始”这篇文章。

    而这里的SLink字段有两个作用:

    1、当SyncBlock是活动的时候,这个字段将作为一个队列,保存在这里排队的线程(作为lock对象时)。

    2、当SyncBlock被回收时,这个字段就作为空闲的SyncBlock列表。

    好了,同步块索引的相关用途和结构在、下这三篇文章中基本讨论完了。没想到这么一个小小的,不起眼的同步块索引却有这么一番作用。从这个同步块索引的使用上,也可以看得出来微软的CLR Team在设计的时候,对内存、性能可谓斤斤计较,充分的利用每一个bit,一个bit的不同就会表示不同的作用。

  • 相关阅读:
    Reactive Extensions (Rx) 入门(5) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(4) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(3) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(2) —— 安装 Reactive Extensions
    Reactive Extensions (Rx) 入门(1) —— Reactive Extensions 概要
    Xamarin NuGet 缓存包导致 already added : Landroid/support/annotation/AnimRes 问题解决方案
    Android 系统Action大全
    Xamarin Forms 实现发送通知点击跳转
    如何理解灰度发布
    推荐一款分布式微服务框架 Surging
  • 原文地址:https://www.cnblogs.com/qianyz/p/2224922.html
Copyright © 2011-2022 走看看