5
MyObject obj = new MyObject();

我知道'new'关键字将调用构造函数并在托管堆中初始化对象。

我的问题是 CLR 如何执行以下操作。

  1. CLR如何执行上述行?
  2. CLR如何为对象分配内存?
  3. CLR如何确定对象的大小?
  4. 如果没有空间为堆中的对象分配内存,CLR 将如何知道它?
4

1 回答 1

2

当创建引用类型(类、委托、接口、字符串或对象)时,它被分配到堆上。Net 有四个不同的堆:(gen0、gen1、gen2)(小对象堆)和 LOH(大对象)堆)。根据创建时间(从 gen0 到 gen1 到 gen2 等),所有 85k 或更小的东西都放在前三个堆之一。大于 85k 的对象被放置在 LOH 上。LOH 永远不会被压缩,所以最终,我正在做的类型的分配最终会导致 OOM 错误,因为对象分散在该内存空间中。这些被称为托管堆。

要创建一个对象,您需要做的就是使用 new 关键字;.NET 将负责创建、初始化对象并将其放置在正确的堆上,并保留任何必要的额外内存。之后,您几乎可以忘记该对象,因为完成后您不必删除它。

当您使用 new 关键字创建引用类型对象时,它被放置在堆上,并且它的引用主要用于当前正在运行的堆栈中。还有其他可能的来源,您的对象可以用作参考:

  1. 全局/静态对象引用
  2. CPU 寄存器
  3. 对象终结参考(稍后更多)
  4. 互操作引用(传递给 COM/API 调用的 .NET 对象)
  5. 堆栈引用(这里主要使用)

这 5 个实际上是 GC 根节点,从中形成对象引用层次结构。想象一下经典的 Customer 类,它通常有一个存储 Order 类的集合。当一个 Order 被添加到 order 集合中时,集合本身会保存对添加的 order 的引用。如果 Customer 类的实例也有对它的堆栈引用。

这就是复杂对象的层次结构的形成方式,这就是 GC 查看引用的方式。

例如。客户对象的堆栈引用-> 对订单列表对象的引用-> 引用单个订单。

任何从这 5 个根中松散引用的东西都容易发生 GC。

如何将内存分配给对象有点复杂,并且它通常随着 MKK 的指定而随时间增长http://msdn.microsoft.com/en-us/magazine/cc163791.aspx

一个简单的例子可能是:

class MyClass 
{ 
    string Test="Hello world Wazzup!"; 
    byte[] data=new byte[86000];  
}

很容易假设分配时 MyClass 的大小包括:

• 19 个字符

• 86,000 字节。

事实上,对象的大小将只包括一般类的东西,以及存储对象指向字符串和字节数组(类级变量)所需的内存,然后将它们分别分配到堆上。字符串将在 SOH 上分配,其对象引用由类的实例持有;字节数组将被分配到 LOH,因为它大于 85 KB。

SOH 可以被压缩,里面不会有碎片,而 LOH 可以在内存中有碎片。

问候。

于 2012-06-14T06:07:05.453 回答