当我给MyObject obj = new MyObject()时发生了什么

时间:2012-06-14 05:30:13

标签: c# .net garbage-collection clr

MyObject obj = new MyObject();

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

我的问题是CLR如何做到以下。

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

1 个答案:

答案 0 :(得分:2)

当创建引用类型(类,委托,接口,字符串或对象)时,它被分配到堆上.Net有四个不同的堆:(gen0,gen1,gen2)(小对象堆) )和LOH(大对象堆)。根据创建时间(从gen0移动到gen1到gen2等),前五个堆之一的85k或更小的所有内容都会出现。大于85k的物体放置在LOH上。 LOH永远不会被压缩,因此最终,I类型的分配最终将导致OOM错误,因为对象散布在该内存空间周围。这些被称为托管堆。

要创建对象,您只需使用new关键字; .NET将负责创建,初始化和将对象放在正确的堆上,并保留必要的额外内存。在那之后你几乎可以忘记那个对象,因为当你完成它时你不必删除它。

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

  1. 全局/静态对象引用
  2. CPU注册
  3. 对象完成引用(稍后更新)
  4. 互操作引用(传递给COM / API调用的.NET对象)
  5. 堆栈引用(主要用于此处)
  6. 这5个实际上是形成对象引用层次结构的GC根节点。想象一下经典的Customer类,它通常有一个存储Order类的集合。将订单添加到订单集合后,集合本身将保留对添加订单的引用。如果Customer类的实例也有一个堆栈引用。

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

    E:克。 Customer对象的stack-reference - >对订单的List对象的引用 - >参考个别订单。

    任何从这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可能会在内存中碎片化。

    问候。