.NET 中由 CLR 负责内存管理。
由 CLR 管理的内存区域主要有:
线程的堆栈 :用于分配给值类型的实例。堆栈主要由操作系统管理,不受 GC 的控制。当值类型所处的方法结束,相应的存储单元自动释放。执行效率高,但容量小。
对于局部的值类型变量,操作系统维护着一个堆栈指针来指向下一段自由空间。由高地址向低地址填充。
GC 堆 :用于分配给小对象实例。如果引用类型对象的实例大小小于 85000Byte, 实例将被分配于 GC 堆上。 GC 堆可能会被压缩。
LOH ( Large Object Heap ) :用于分配给大对象实例。当引用类型对象的实例大小不小于 85000Byte 时,实例将被分配在 LOH 上。不会被压缩,且只有在完全 GC 回收时才被回收。
托管堆 : .NET 应用程序在进程初始化之后, CLR 会在进程的可用地址空间中保留一段地址空间,称为托管堆。它是进程中可用地址空间中的一段,因此不对应任何物理内存。
托管堆分为 GC Heap 和 Loader Heap 。 GC Heap 用于存储对象实例,受 GC 管理;而 Loader Heap 又分为 High-Frequency Heap 、 Low-Frequency Heap 和 Stub Heap ,不同的 heap 又存储不同的信息。 Loader Heap 中最重要的信息是元数据 (MetaData) 相关的信息,也就是 Type 对象,每个 Type 对象在 Loader Heap 上体现为一个 Method Table , Method Table 中记录了存储的元数据信息,如基类型、静态字段、实现的接口、所有的方法等。 Loader Heap 的生命周期为从 AppDomain 创建到卸载。
托管堆中维护着一个 NextObjPtr 指针 , 指向托管堆中下一个新建对象的位置。 CLR 初始化时, NextObjPtr 指向托管堆的基地址,于堆栈相反,由低地址向高地址填充。
每个对象创建时都包含 2 下列两个附加成员:
TypeHandle, 类型句柄,指向对应实例的 Method Table. 4Bytes.
SyncBlockIndex, 用于线程同步,指向一块被称为 Synchronization Block 的内存块,用于管理对象同步。 4Bytes.