简体   繁体   English

可变结构与类?

[英]Mutable struct vs. class?

I'm unsure about whether to use a mutable struct or a mutable class. 我不确定是使用可变结构还是可变类。 My program stores an array with a lot of objects. 我的程序存储了一个包含大量对象的数组。 I've noticed that using a class doubles the amount of memory needed. 我注意到使用类会使所需的内存量翻倍。 However, I want the objects to be mutable, and I've been told that using mutable structs is evil. 但是,我希望这些对象是可变的,并且我被告知使用可变结构是邪恶的。 This is what my type looks like: 这就是我的类型:

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
}

Allocating a large amount of objects like this (notice that both codes below are run 81 times): 像这样分配大量的对象(注意下面的两个代码都运行了81次):

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

uses about 35 MiB of memory, whilst doing it like this: 使用大约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();

uses about 100 MiB of ram. 使用大约100 MiB的ram。

So to conclude, my question is as follows: 总而言之,我的问题如下:

Should I use a struct or a class for my Block type? 我应该为块类型使用结构或类吗? Instances should be mutable and store a few values plus one object reference. 实例应该是可变的并存储一些值加上一个对象引用。

First off, if you really want to save memory then don't be using a struct or a class. 首先,如果你真的想节省内存,那么不要使用结构或类。

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

You want to tightly pack similar things together in memory . 你想在内存中将类似的东西紧紧包装在一起 You never want to put a byte next to a reference in a struct if you can possibly avoid it; 如果你可以避免它,你永远不想在结构中的引用旁边放一个字节; such a struct will waste three to seven bytes automatically. 这样的结构会自动浪费三到七个字节。 References have to be word-aligned in .NET. 引用必须在.NET中进行字对齐。

Second, I'm assuming that you're building a voxel system here. 其次,我假设你在这里建造一个体素系统。 There might be a better way to represent the voxels than a 3-d array, depending on their distribution. 根据它们的分布,可能有更好的方式来表示体素而不是三维阵列。 If you are going to be making a truly enormous number of these things then store them in an immutable octree . 如果你要制作真正大量的这些东西,那么将它们存储在一个不可变的八叉树中 By using the persistence properties of the immutable octree you can make cubic structures with quadrillions of voxels in them so long as the universe you are representing is "clumpy". 通过使用不可变八叉树的持久性属性,只要您所代表的宇宙是“块状”,您就可以在其中制作具有数十亿个体素的立方结构。 That is, there are large regions of similarity throughout the world. 也就是说,世界上存在大的相似区域。 You trade somewhat larger O(lg n) time for accessing and changing elements, but you get to have way, way more elements to work with. 你可以用更大的O(lg n)时间来访问和更改元素,但是你可以使用更多的元素。

Third, "ID" is a really bad way to represent the concept of "type". 第三,“ID”是表示“类型”概念的一种非常糟糕的方式。 When I see "ID" I assume that the number uniquely identifies the element, not describes it. 当我看到“ID”时,我假设该数字唯一地标识该元素,而不是描述它。 Consider changing the name to something less confusing. 考虑将名称更改为不那么令人困惑的东西。

Fourth, how many of the elements have metadata? 第四,有多少元素有元数据? You can probably do far better than an array of references if the number of elements with metadata is small compared to the total number of elements. 如果具有元数据的元素数量与元素总数相比较小,则可能比引用数组更好。 Consider a sparse array approach; 考虑一种稀疏数组方法; sparse arrays are much more space efficient. 稀疏数组的空间效率更高。

Do they really have to be mutable? 他们真的必须是可变的吗? You could always make it an immutable struct with methods to create a new value with one field different: 你总是可以使用一个不可变的结构来创建一个不同的字段的新值:

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);
    }
}

I'm still not sure whether I'd make it a struct, to be honest - but I'd try to make it immutable either way, I suspect. 我还不确定我是否会把它变成一个结构,说实话 - 但是我怀疑,无论如何我都试图让它成为一个不可变的结构。

What are your performance requirements in terms of both memory and speed? 在内存和速度方面,您的性能要求是什么? How close does an immutable class come to those requirements? 不可变类有多接近这些要求?

An array of structs will offer better storage efficiency than an array of immutable references to distinct class instances having the same fields, because the latter will require all of the memory required by the former, in addition to memory to manage the class instances and memory required to hold the references. 结构数组将提供比具有相同字段的不同类实例的不可变引用数组更好的存储效率,因为后者将需要前者所需的所有内存,除了内存以管理所需的类实例和内存持有参考文献。 All that having been said, your struct as designed has a very inefficient layout. 所有这一切,你的结构设计有一个非常低效的布局。 If you're really concerned about space, and every item in fact needs to independently store a byte, a Boolean, and a class reference, your best bet may be to either have two arrays of byte (a byte is actually smaller than a Boolean) and an array of class references, or else have an array of bytes, an array with 1/32 as many elements of something like BitVector32, and an array of class references. 如果你真的关心空间,并且每个项目实际上需要独立存储一个字节,一个布尔值和一个类引用,你最好的选择是要么有两个字节数组(一个字节实际上小于一个布尔值) )和一个类引用数组,或者有一个字节数组,一个像BitVector32这样的1/32元素的数组,以及一个类引用数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM