Как выделить непрерывную и фиксированную память в .NET Core - PullRequest
2 голосов
/ 26 октября 2019

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

Вот структура данных, которую я использую.

public sealed class Buffer<TValue> : IEnumerable<BufferElement<TValue>> where TValue : new()
{
    public Buffer(int capacity)
    {
        Count = 0;
        Capacity = capacity;
        Elements = new BufferElement<TValue>[capacity];

        for (var index = 0; index < Elements.Length; index++)
        {
            Elements[index] = new BufferElement<TValue>();
        }
    }

    public int Count { get; private set; }

    public int Capacity { get; private set; }

    private int ActiveCount { get; set; }

    private BufferElement<TValue>[] Elements { get; }

    public BufferElement<TValue> Activate()
    {
        if (Count == ActiveCount) Count = 0;

        var bufferElement = Elements[Count++];

        if (!bufferElement.Active)
        {
            bufferElement.Active = true;
            ActiveCount++;
        }

        return bufferElement;
    }

    public void Deactivate(BufferElement element)
    {
        if (!element.Active) return;

        element.Active = false;

        var lhs = element.Index;
        var rhs = --ActiveCount;

        Elements[lhs] = Elements[rhs];
        Elements[rhs] = element;

        Elements[lhs].Index = lhs;
        Elements[rhs].Index = rhs;
    }
}

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

Я хотел бы иметь все свои буферыкоторые содержат физические объекты, чтобы не выполнять предварительные проверки безопасности и быть фиксированными в непрерывной памяти, если это возможно. Я считаю, что это должно быть возможным, поскольку размер каждого буфера фиксирован, а размеры элементов (твердое тело, частица, сила) также фиксированы.

Кажется, что есть много способов управления памятьюв C #, и мне трудно понять, что было бы правильным для меня в этой ситуации.

Теперь вопрос сводится к трем частям:

  1. Можно ли это сделать?
  2. Если да, то какой метод управления памятью лучше всего?
  3. И как будет выглядеть правильная реализация?

1 Ответ

1 голос
/ 26 октября 2019

Во-первых, да, это можно сделать. Во-вторых, best действительно зависит, так как существует множество компромиссов, и это быстро становится самоуверенным постом. В-третьих, самая легкая альтернатива - использовать ключевое слово fixed для выделения массива в контексте unsafe (здесь нет проверок безопасности для массивов и позволяет использовать указатели стиля C) и закрепить его адрес так, чтобы он нене меняется, хотя использование Span или Memory может быть проще, подход низкого уровня fixed и unsafe может дать лучшую производительность при правильном использовании. Проверьте это , это официальные документы, и он заполнен аккуратными примерами. Последний совет: попробуйте переключиться на struct вместо , если это возможно , у них нет накладных расходов памяти и более высокая плотность памяти, что дает гораздо лучшее время доступа к кэшу, так как в него помещается гораздо больше.

...