可变结构与类?

发布于 2025-01-07 06:49:42 字数 876 浏览 0 评论 0原文

我不确定是否使用可变结构或可变类。 我的程序存储一个包含很多对象的数组。 我注意到使用类会使所需的内存量增加一倍。但是,我希望对象是可变的,并且有人告诉我使用可变结构是邪恶的。 这就是我的类型的样子:

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。

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

我应该为我的块类型使用结构体还是类?实例应该是可变的,并存储一些值和一个对象引用。

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):

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

uses about 35 MiB of memory, whilst doing it like this:

// 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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

音栖息无 2025-01-14 06:49:42

首先,如果您确实想节省内存,那么就不要使用结构或类。

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

您希望将相似的内容紧密地打包在内存中。如果可以避免的话,您永远不想在结构中的引用旁边放置一个字节;这样的结构会自动浪费三到七个字节。 引用必须在 .NET 中字对齐。

其次,我假设您正在此处构建体素系统。可能有比 3 维数组更好的方法来表示体素,具体取决于体素的分布。如果您要制作大量这些东西,那么请将它们存储在不可变的八叉树中。通过使用不可变八叉树的持久性属性,只要您所代表的宇宙是“块状”的,您就可以创建其中包含千万体素的立方结构。也就是说,世界各地存在很大的相似区域。您用更大的 O(lg n) 时间来访问和更改元素,但您可以使用更多的元素。

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

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

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.

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.

Third, "ID" is a really bad way to represent the concept of "type". When I see "ID" I assume that the number uniquely identifies the element, not describes it. 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.

黑凤梨 2025-01-14 06:49:42

它们真的必须是可变的吗?您始终可以将其设为不可变的结构,并使用方法来创建一个具有不同字段的新值:

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

说实话,我仍然不确定是否会将其设为一个结构 - 但我会尝试以任何一种方式使其不可变,我怀疑。

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

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?

阿楠 2025-01-14 06:49:42

结构数组比对具有相同字段的不同类实例的不可变引用数组提供更好的存储效率,因为除了管理类实例的内存和所需的内存之外,后者还需要前者所需的所有内存保存参考文献。话虽如此,您设计的结构的布局非常低效。如果您真的关心空间,并且实际上每个项目都需要独立存储一个字节、一个布尔值和一个类引用,那么您最好的选择可能是拥有两个字节数组(一个字节实际上小于一个布尔值) )和一个类引用数组,或者有一个字节数组、一个元素数量为 BitVector32 之类的 1/32 的数组,以及一个类引用数组。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文