类在内存中的结构

每当在堆中创建对象时,每个对象都会获得两个与它关联的附加开销字段。 第一个开销字段MethodTablePointer 包含类型的方法表的内存地址。 基本上,该指针使获得有关堆中的任何对象的类型信息成为可能。实际上,当您在内部调用 System.Object 的 GetType 方法时,该方法会按照对象的 MethodTablePointer 字段来确定该对象的类型。 第二个开销字段名为 SyncBlockIndex,它包含 SyncBlock 缓存的 32 位有符号的整数索引。

当构建某个对象时,该对象的 SyncBlockIndex 会被初始化为一个负值,以表明它根本不引用任何 SyncBlock。然后,当调用一个方法以同步对该对象的访问时,CLR 会在它的缓存中查找一个可用的 SyncBlock,并且将该对象的 SyncBlockIndex 设置为引用该 SyncBlock。换言之,当对象需要同步字段时,SyncBlock 被即时与该对象相关联。当不再有其他要同步对象访问的线程时,该对象的 SyncBlockIndex 被重置为一个负数,并且 SyncBlock 可在将来用来与其他对象相关联。

有关该想法的具体表示,请参见下图。 mismsdnmagissues0301netfig02.gif 在该图的“CLR 数据结构”部分中,您可以看到对于系统了解的每个类型,都有一个数据结构;您还可以看到 SyncBlock 结构集。在该图的“托管堆”部分中,您可以看到创建了三个对象:ObjectA、ObjectB 和 ObjectC。每个对象的 MethodTablePointer 字段都引用类型的方法表。从该方法表中,可以知道每个对象的类型。因此,我们可以容易地看到 ObjectA 和 ObjectB 是 SomeType 类型的实例,而 ObjectC 是 AnotherType 类型的实例。

您将注意到,ObjectA 的 SyncBlockIndex 开销字段被设置为 0。这表明 SyncBlock #0 当前由 ObjectA 使用。 另一方面,ObjectB 的 SyncBlockIndex 字段被设置为 -1,这表明 ObjectB 不具有与它关联以供它使用的 SyncBlock。 最后,ObjectC 的 SyncBlockIndex 字段被设置为 2,这表明它使用的是 SyncBlock #2。 在此处我已经介绍的示例中,SyncBlock #1 未使用,并且可能在将来与某个对象相关联。

因此,从逻辑上讲,您会看到堆中的每个对象都具有一个与其相关联的 SyncBlock,并且可以使用它来进行快速的独占的线程同步。但是,从物理上讲,只有在需要 SyncBlock 结构时才会将它们与对象相关联;当不再需要它们时,则会解除它们与对象之间的关联。这说明内存使用很有效。顺便说一句,如有必要,则 SyncBlock 缓存能够创建更多的 SyncBlocks,因此如果要同时对很多对象进行同步,则无需担心系统会耗尽它们。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值