2

当 CLR 将对象放在大对象堆上时,是“全有还是全无”的交易?类/结构成员是否“拆分”并放置在不同的堆中?

class OneBigObject
{
    byte[] bigObject;

    public OneBigObject()
    {
        bigObject = new byte[100000];
    }
}

class TwoSmallObjects
{
    byte[] smallObject1;
    byte[] smallObject2;

    public TwoSmallObjects()
    {
        smallObject1 = new byte[50000];
        smallObject2 = new byte[50000];
    }
}

class MixedSizeObjects
{
    byte[] smallObject1;
    byte[] smallObject2;
    byte[] bigObject;

    public MixedSizeObjects()
    {
        smallObject1 = new byte[50000];
        smallObject2 = new byte[50000];
        bigObject = new byte[100000];
    }
}

OneBigObject oneBigObject = new OneBigObject();
TwoSmallObjects twoObjects = new TwoSmallObjects();
MixedSizeObjects mixedSizeObjects = new MixedSizeObjects();

TwoSmallObjects由于总大小超过 85,000 字节,是否放置在大对象堆上?即使两个成员都单独低于阈值?怎么样MixedSizeObjects

4

2 回答 2

3

您分配的每个字节数组都与封闭类分开处理。所以 OneBigObject 实际上是两个不同的 CLR 对象。一个是 OneBigObject 实例,它非常小并且只包含一个引用字段。另一个是 100,000 个实例的实际字节数组。同样的原则也适用于其他类。

类和结构没有分开。没有必要,因为很难想象有人会创建一个具有足够实际字段以使其存储大小为 85k 的类型。像您的示例一样,看起来很大的对象实际上由引用和引用数组组成,因此根本不是很大。

于 2011-10-25T01:28:24.077 回答
1

的大小TwoSmallObjects(忽略每个对象的开销)仅为 8 个字节(在 64 位进程中为 16 个)。同样,大小MixedSizeObjects仅为 24 字节(64 位为 48)。

因此,要回答您的问题,这些对象都不会进入 LOH。他们引用的数组可能取决于每个单独数组的大小。

我无法想象一个按照您期望的方式工作的系统将如何工作。特别是考虑到构造函数在分配对象后运行。分配器在您实际执行此操作之前如何知道您要为其字段分配什么?如果你这样做,它应该将对象移动到 LOH 吗?如果它没有任何帮助,为什么它会做所有这些工作。

另一件事可能会有所帮助:如果您有一个引用类型(并且数组是一个),则该字段不包含该对象。它只包含参考

于 2011-10-25T01:26:40.050 回答