【问题标题】:What is happening when I give MyObject obj = new MyObject()当我给 MyObject obj = new MyObject() 时会发生什么
【发布时间】:2012-06-14 05:30:12
【问题描述】:
MyObject obj = new MyObject();

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

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

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

【问题讨论】:

  • 我建议您阅读 CLR via C# -- Jeffrey Richter 以获得更好的见解

标签: c# .net garbage-collection clr


【解决方案1】:

当一个引用类型被创建(类、委托、接口、字符串或对象)时,它被分配到堆上。网络有四个不同的堆:(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可以被compacted,里面不会有碎片,而LOH可以在内存中有碎片。

问候。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-08
    • 2011-09-13
    • 2019-09-12
    • 2011-02-05
    • 1970-01-01
    • 2019-11-05
    • 2016-11-29
    • 1970-01-01
    相关资源
    最近更新 更多