【问题标题】:CLR Sync Block AddressCLR 同步块地址
【发布时间】:2015-08-21 20:03:57
【问题描述】:

当我这样做时:

public class Employee
{
    public int exp;
}

class Program
{
    static void Main(string[] args)
    {            
        Employee o1 = new Employee();
        o1.exp = 3;
        lock (o1)
        {
            //I am here
        }
    }
}

并获取o1的内存(地址为0x022cf940):

我意识到下面提到的几件事:

  1. 绿色矩形为同步块,为12
  2. 蓝色矩形是4字节地址类型
  3. 红色矩形为4字节整数,即3;

问题:同步块的空间在哪里,如何找到它? “12”代表什么?

【问题讨论】:

  • 您的图像表明这是一个 32 位系统。绿色矩形是您的 Syncblk,值为 12(以及标志 BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX = 0x08000000),蓝色是您的 TypeHandle,红色是您的 exp 字段的值。您是在问我们在哪里可以找到 Syncblk 条目表? msdn.microsoft.com/en-us/magazine/cc163791.aspx#S7
  • 也许 syncblk.h 代码会有所帮助? github.com/dotnet/coreclr/blob/master/src/vm/syncblk.h
  • 值 (0x12) 是可移动表的索引。该表的位置只是 CLR 关心的问题,程序员不需要知道。因此没有 API 可以找到。
  • Henk Holterman - 正如 Hans Passant 所说,是 System.Threading.Thread.CurrentThread.ManagedThreadId。

标签: c# heap-memory clr


【解决方案1】:

同步块有不止一种用途。它可以存储 Object.GetHashCode() 的值,以便对象在再次调用 GetHashCode() 时始终返回相同的哈希码。它可以存储 lock 语句的所有者线程的 ID。它有几个专用位,例如指示对象的终结器已运行。它可以存储分配的同步块的句柄,当一个线程调用GetHashCode 使用锁并且信息不再适合同步块时,这是必需的。它进行了大量的微优化。

您的情况是简单的情况,仅调用了 lock 并且没有打开任何专用位。所以你看到锁的所有者,0x12 = 18 是拥有锁的线程的 Thread.ManagedThreadId。当您需要解决死锁问题时,它可以派上用场。

当您右键单击窗口并选择“4-byte Integer”时,可以使调试器显示更易于解释。蓝色矩形是对象的方法表指针(又名“类型句柄”)。它指示对象的类型,Object.GetType() 使用它。红色矩形是对象开始存储其字段的位置。由于你的只有exp字段,而且它的类型是Int32,所以你可以看到后面的3。

【讨论】:

  • 所以,是 System.Threading.Thread.CurrentThread.ManagedThreadId。谢谢!
  • @Hans,如果同步块是 4 个字节(或 8 个字节),那么它可以保存哈希码、锁所有者线程 ID、分配的同步块的句柄等之一。但是不要这些东西不需要所有同步块中的空间吗?那么指示这些东西中的哪一个被保存的位或位在哪里? GC 等的位在哪里。
  • 是的,这些就是我所说的“专用位”。 Object.GetHashCode() 不使用 32 位哈希码,它使用 26 位。没问题,你永远不会创建 40 亿个对象。如果您想了解更多,请点击按钮。
  • 本例中的值表示 SyncBlock 表中的索引条目,您必须在其中查找锁所有者。您所描述的是当BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX = 0x08000000 被清除(ThinLock)。 github.com/dotnet/coreclr/blob/… 表示: > 如果 BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX 清晰,则头部 dword 的其余部分布局如下:低 10 位(位 0 到 9)是 线程 id 用于 thin lock...如果设置了 BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX...dword 的其余部分是同步块 index
  • 这是不正确的。只有当对象被用作锁并且 GetHashCode() 被调用时,才会使用同步块。在正确设计的代码中应该永远不会。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-16
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
相关资源
最近更新 更多