0

在使用 CLR Profiler 进行一些实验后,我发现:

Node[,] n = new Node[100,23]; //'84,028 bytes, is not placed in LOH
Node[,] n = new Node[100,24]; //'86,428 bytes, is 

    public struct Node {
        public int Value;
        public Point Point;
        public Color Color;
        public bool Handled;
        public Object Tag;
    }

在运行时,我如何知道在大对象堆 (LOH) 中分配了结构数组(或任何数组)?

4

3 回答 3

2

任何大于 85,000 字节的对象都将存储在 LOH 中。这是一篇关于.Net 内存管理的精彩博文。

于 2010-05-06T00:33:54.707 回答
1

您可以在分配后立即找到。使用 GC.GetGeneration(object) 重载来获取对象所在的世代号。对于 LOH,这将是 2。

Node[,] n = new Node[100,23]; 
// GC.GetGeneration(n) should give 0
Node[,] n = new Node[100,24]; 
// GC.GetGeneration(n) should give 2

请注意,这有一些限制,并且绝不是生产代码的正确方法,我假设:如果您稍后查询该数字,则该对象可能已经从 Gen 0 移动到 Gen 2。我无法区分 Gen2(小对象)堆和 LOH。此外,对于我测试过的所有 .NET 版本,LOH 上的对象返回的数量是 2。但是我在真正的规范中找不到这个,所以它也可能是一个改变的问题。

于 2011-01-27T10:50:27.663 回答
1

根据您的评论,我认为您实际上不需要知道该对象是否会继续进行 LOH。当您真正想做的只是在用户输入“太大”的值时向用户显示警告时,这是否是应用程序减速的实际原因是无关紧要的。

所以我会建议一些更简单的方法:只需使用一些试错法来确定截止值。如果他们输入的大小超过了您的试错值,则显示警告。

至于您的实际性能问题,您可以简单地分配一堆“较小”的一维数组,而不是分配一个大的二维数组。代替:

Node[,] n = new Node[100,100]; // this will go the LOH

你会这样做:

Node[][] n = new Node[100][];
for(int i = 0; i < n.Length; i++) {
    n[i] = new Node[100];  // none of these will be on the LOH
}

您仍然拥有相同数量的节点,但 LOH 上不会发生任何事情。就个人而言,我认为您可能会发现性能实际上并没有太大的不同,但尝试一下可能是值得的。

于 2010-05-06T01:07:42.987 回答