类 将锁对象绑定到它们有充分的理由吗?

Is there a good reason why classes have lock objects tied to them?

如果我理解正确,class 的任何实例默认都有一个 锁定对象

证明

当我们进入“锁定”时,我们实际数据上方的内存就会被设置。

var d = new Data();

d.x0 = 1;
d.x1 = 2;
d.x2 = 3;
d.x3 = 4;

lock (d) 
{   // <---- when we're here.
    
}

然后离开范围。

var d = new Data();

d.x0 = 1;
d.x1 = 2;
d.x2 = 3;
d.x3 = 4;

lock (d) 
{   
    
}    // <---- when we're here.

然后内存中的1就消失了

详情

现在如果你想看看它在没有 lock 关键字的情况下如何表现 -> 让我们创建 2 类 并在 Release 模式下执行我们的代码(这样我们就可以得到 right/optimized版本+内存可读性更强)。

var d1 = new Data();

d1.x0 = 1;
d1.x1 = 1;
d1.x2 = 1;
d1.x3 = 1;

var d2 = new Data();

d2.x0 = 2;
d2.x1 = 2;
d2.x2 = 2;
d2.x3 = 2;

所以没有使用 lock。现在让我们看看内存是如何对齐的。正如你在图片中看到的:它 NOT 在第一个实例之后立即分配我们的第二个实例,有 00 00 00 00 00 00 00 00 的间隙,这证明 C# 为每个实例分配了额外的内存实例。并测试第一个片段,您会发现它确实用于锁定目的。

问题

我们这样做有充分的理由吗?我的意思是大多数时候我们不会锁定我们的对象。这不是浪费吗?

情况比那复杂一点。所有 objects 都有一个 header 和一个方法 table 指针,每个都是 4 或 8 个字节,具体取决于平台。值得注意的是 header 用于比锁定更多的事情。

  1. Locking
  2. GC information. E.g.
    • Bits to mark objects
    • Generation of the object
    • Whether the object is pinned
  3. Hashcode (for GetHashCode support)
  4. Size of the object

来源:Managed object internals, Part 1. The layout, CLR Managed Object overhead

如果没有第一手知识,很难找出内部团队决策背后的原因。所以这是基于推测。

他们可能希望 header 与指针大小相同以保持对齐。由于 header 中的所有位都没有用于其他目的,因此它们还不如将其中一些用于锁定。请注意,header 中的位可能不足以将其用作锁。如果是这种情况,一些位将被重新用作指向单独 table.

的指针

As you may know, every managed object has an auxiliary field for every object called the object header. The header itself can be used for different purposes and can keep different information based on the current object’s state.

The CLR can store object’s hash code, domain specific information, lock-related data and some other stuff at the same time. Apparently, 4 bytes of the object header is simply not enough for all of that. So, the CLR will create an auxiliary data structure called sync block table and will keep just an index in the header itself. But the CLR will try to avoid that and will try to put as much data in the header itself as possible.

来源:Managed object internals, Part 2. Object header layout and the cost of locking

因此,声称“类 已将锁 objects 绑定到它们”是不正确的。相反,objectsheaders,header的一部分包含与锁定相关的信息。