0

我正在尝试调试旧网站中 CPU 使用率高的原因,并且通过查看 DebugDiag 中的一些分析,我怀疑 LOH 上的对象数量以及随后的 GC 收集可能是一个原因。在一个 .dbg 文件中,我们在 LOH 上有约 3.5gb,其中大部分对象是字符串。

我知道,要在 LOH 上运行的对象,它们必须超过 85000 字节。

我不确定这是否是指例如单个数组。或者它可以引用一个大对象图吗?

我的意思是如果我有对象 Foo,它包含 n 个其他对象,每个对象本身都包含 n 个对象。如果这些对象中的每一个都包含字符串,并且 Foo(和所有子对象)的总大小大于 85000 字节,是否会将 Foo 放置在 LOH 上?或者,如果在 Foo 对象图中的某个地方有一个大于 85000 字节的数组,那么它是否只是放置在 LOH 上的那个数组?

谢谢。

4

3 回答 3

5

没错,如果数组大于 85000,那么它将被视为 LOH 而不是整个对象。为了在这里解释这一点,我创建了示例。

   class Program
    {
        static void Main(string[] args)
        {
            Obj o = new Obj();
            o.Allocate(85000);
            Console.WriteLine(System.GC.GetGeneration(o));
            Console.WriteLine(System.GC.GetGeneration(o.items));
            Console.WriteLine(System.GC.GetGeneration(o.items2));
            Console.WriteLine(System.GC.GetGeneration(o.Data));
            Console.ReadLine();           
        }

        class Obj
        {
            public byte[] items = null;

            public byte[] items2 = null;

            public string Data = string.Empty;

            public void Allocate(int i)
            {
                items = new byte[i];
                items2 = new byte[10];
                Data = System.Text.Encoding.UTF8.GetString(items);
            }
        }
    }

如果您注意到该字符串数据,请在此处。它也被认为是 LOH,因为字符串是字符数组。Items2 不是 LOH,Items 是 LOH,但实际对象 o 不是 LOH。

于 2014-12-09T06:40:07.130 回答
1

只有大于 85,000 字节的单个对象才会进入 LOH。只要没有单个对象超过限制,对象图的总和可以超过该值,但不在 LOH 中。字节数组和字符串是最典型的罪魁祸首。

于 2014-12-09T06:44:39.647 回答
0

我同意@daaspek 和@dotnetstep。

例如,在@dotnetstep 的示例中, o 在 32 位机器上的大小应为 12 字节,在 64 位机器上应为 24 字节。

Obj 类中定义的所有字段都是引用类型,因此所有 Obj 存储都是指向创建其子元素(在本例中为数组)的堆位置的指针。

现在这些对象中的每一个都是数组(字符串是 char[] 的数组),因此如果它们超过 85000 字节的限制,它们可以被放置在 LOH 上。

每次创建常规对象时,可以将其放置在 LOH 上的唯一方法是,如果所有字段都是REFERENCE类型,则它在 32 位机器上具有 21251 个或更多字段,在 64 位机器上具有 10626 个或更多字段。出于所有意图和目的,这通常不是一种实用的类创建;遇到这样的班级将是极其罕见的。

在包含的字段是结构的情况下,它们被认为是类定义的一部分。因此,结构的内容不是保存一个 4 字节的堆地址,而是类布局的一部分 - 大量具有大型结构的字段可能不会很快达到 85000 字节的限制,但它仍然可能被破坏。

于 2014-12-16T09:53:58.007 回答