可变结构与类?

时间:2012-02-17 21:11:33

标签: c# class memory struct mutable

我不确定是使用可变结构还是可变类。 我的程序存储了一个包含大量对象的数组。 我注意到使用类会使所需的内存量翻倍。但是,我希望这些对象是可变的,并且我被告知使用可变结构是邪恶的。 这就是我的类型:

struct /* or class */ Block
{
    public byte ID;
    public bool HasMetaData; // not sure whether HasMetaData == false or
                             // MetaData == null is faster, might remove this
    public BlockMetaData MetaData; // BlockMetaData is always a class reference
}

分配大量这样的对象(注意下面的两个代码都运行了81次):

// struct
Block[,,] blocks = new Block[16, 256, 16];

使用大约35 MiB的内存,同时这样做:

// class
Block[,,] blocks = new Block[16, 256, 16];
for (int z = 0; z < 16; z++)
for (int y = 0; y < 256; y++)
for (int x = 0; x < 16; x++)
    blocks[x, y, z] = new Block();

使用大约100 MiB的ram。

总而言之,我的问题如下:

我应该为块类型使用结构或类吗?实例应该是可变的并存储一些值加上一个对象引用。

3 个答案:

答案 0 :(得分:16)

首先,如果你真的想节省内存,那就不要使用结构或类。

byte[,,] blockTypes = new byte[16, 256, 16]; 
BlockMetaData[,,] blockMetadata = new BlockMetaData[16, 256, 16];

你想在内存中将类似的东西紧紧包装在一起。如果你可以避免它,你永远不想在结构中的引用旁边放一个字节;这样的结构会自动浪费三到七个字节。 引用必须在.NET中进行字对齐。

其次,我假设你在这里建造一个体素系统。根据它们的分布,可能有更好的方式来表示体素而不是三维阵列。如果你要制作大量的这些东西,那么将它们存储在不可变的八叉树中。通过使用不可变八叉树的持久性属性,只要您所代表的宇宙是“块状”,您就可以在其中使用 quadrillions 的体素制作立方结构。也就是说,世界上存在大的相似区域。你可以用更大的O(lg n)时间来访问和更改元素,但是你可以使用更多元素来处理。

第三,“ID”是表示“类型”概念的一种非常糟糕的方式。当我看到“ID”时,我认为唯一标识元素的数字,而不是描述它。考虑将名称更改为不那么混乱。

第四,有多少元素有元数据?如果具有元数据的元素数量与元素总数相比较小,则可能比引用数组更好。考虑一种稀疏数组方法;稀疏数组的空间效率更高。

答案 1 :(得分:4)

他们真的必须是可变的吗?您总是可以使用一个不同的字段创建一个新值的方法使其成为一个不可变的结构:

struct Block
{
    // I'd definitely get rid of the HasMetaData
    private readonly byte id;
    private readonly BlockMetaData metaData;

    public Block(byte id, BlockMetaData metaData)
    {
        this.id = id;
        this.metaData = metaData;
    }

    public byte Id { get { return id; } }
    public BlockMetaData MetaData { get { return metaData; } }

    public Block WithId(byte newId)
    {
        return new Block(newId, metaData);
    }

    public Block WithMetaData(BlockMetaData newMetaData)
    {
        return new Block(id, newMetaData);
    }
}

我还是不确定我是否会把它变成一个结构,说实话 - 但是我怀疑,无论如何我都试图让它变成一个结构。

在内存和速度方面,您的性能要求是什么?不可变类有多接近这些要求?

答案 2 :(得分:0)

结构数组将提供比具有相同字段的不同类实例的不可变引用数组更好的存储效率,因为后者将需要前者所需的所有内存,除了内存以管理类实例和保存引用所需的内存。所有这一切,你的结构设计有一个非常低效的布局。如果你真的关心空间,并且每个项目实际上需要独立存储一个字节,一个布尔值和一个类引用,你最好的选择是要么有两个字节数组(一个字节实际上小于一个布尔值) )和一个类引用数组,或者有一个字节数组,一个像BitVector32这样的1/32元素的数组,以及一个类引用数组。