Изменчивая структура против класса? - PullRequest
3 голосов
/ 18 февраля 2012

Я не уверен, использовать ли изменяемую структуру или изменяемый класс.Моя программа хранит массив с большим количеством объектов.Я заметил, что использование класса удваивает объем необходимой памяти.Однако я хочу, чтобы объекты были изменяемыми, и мне сказали, что использование изменяемых структур - зло.Вот как выглядит мой тип:

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 МБпамяти, делая это следующим образом:

// 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 МБ оперативной памяти.

Итак, в заключение я задаю следующий вопрос:структура или класс для моего типа блока?Экземпляры должны быть изменяемыми и содержать несколько значений и одну ссылку на объект.

Ответы [ 3 ]

16 голосов
/ 18 февраля 2012

Прежде всего, если вы действительно хотите сэкономить память, не используйте структуру или класс.

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

Вы хотите плотно упаковать похожие вещи в память . Вы никогда не хотите помещать байт рядом со ссылкой в ​​структуре, если можете избежать этого; такая структура будет тратить три-семь байтов автоматически. Ссылки должны быть выровнены по словам в .NET.

Во-вторых, я предполагаю, что вы строите здесь систему вокселей. Может быть лучший способ представления вокселей, чем трехмерный массив, в зависимости от их распределения. Если вы собираетесь делать поистине огромное количество этих вещей, то храните их в неизменном октрее . Используя свойства persistence неизменяемого октри, вы можете создавать кубические структуры с квадриллионами вокселей в них, пока представляемая вами вселенная является "комковатой". То есть во всем мире существуют большие области сходства. Вы тратите немного больше времени на доступ и изменение элементов, но у вас есть способ, с которым больше элементов работает.

В-третьих, «идентификатор» - это действительно плохой способ представить понятие «тип». Когда я вижу «ID», я предполагаю, что число уникально идентифицирует элемент, а не описывает его. Попробуйте сменить имя на что-то менее запутанное.

В-четвертых, сколько элементов имеют метаданные? Вы, вероятно, можете сделать намного лучше, чем массив ссылок, если количество элементов с метаданными мало по сравнению с общим количеством элементов. Рассмотрим подход с разреженными массивами; разреженные массивы намного более компактны.

4 голосов
/ 18 февраля 2012

Они действительно должны быть изменяемыми?Вы всегда можете сделать его неизменной структурой с методами для создания нового значения с другим полем:

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

Я все еще не уверен, если бы я сделал это структурой, если честно - но яя подозреваю, что я попытался бы сделать его неизменным.Насколько близко неизменный класс подходит к этим требованиям?

0 голосов
/ 19 февраля 2012

Массив структур предложит лучшую эффективность хранения, чем массив неизменяемых ссылок на отдельные экземпляры класса, имеющие одинаковые поля, поскольку последнему потребуется вся память, необходимая первому, в дополнение к памяти для управления экземплярами класса и память, необходимая для хранения ссылок. С учетом всего вышесказанного, ваша структура, как задумано, имеет очень неэффективный макет. Если вы действительно беспокоитесь о пространстве, и каждый элемент фактически должен независимо хранить байт, логическое значение и ссылку на класс, лучше всего иметь два массива байтов (байт на самом деле меньше, чем логический). ) и массив ссылок на классы, или же имеют массив байтов, массив с 1/32 таким количеством элементов, как BitVector32, и массив ссылок на классы.

...