Компилятор c # решает использовать stackalloc сам по себе? - PullRequest
4 голосов
/ 14 июля 2009

Я нашел запись в блоге, которая предполагает, что иногда компилятор c # может решить поместить массив в стек вместо кучи:

Повышение производительности за счет распределения стека (.NET Memory Management: Часть 2)

Этот парень утверждает, что:

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

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

Если компилятор c # может сделать такой трюк без использования ключевого слова unsafe, я особенно заинтересован в нем. У меня есть код, который работает на многих маленьких байтовых массивах (длиной 8-10 байт), и поэтому использование кучи для каждого нового байта [...] - пустая трата времени и памяти (особенно то, что каждый объект в куче имеет 8-байтовые издержки нужен для сборщика мусора).

РЕДАКТИРОВАТЬ: Я просто хочу описать, почему это важно для меня:
Я пишу библиотеку, которая взаимодействует со смарт-картой Gemalto.NET, в которой может работать код .net. Когда я вызываю метод, который возвращает что-то, смарт-карта возвращает 8 байтов, которые описывают точный тип возвращаемого значения. Эти 8 байтов рассчитываются с использованием хеша md5 и конкатенации некоторых байтовых массивов.
Проблема в том, что когда у меня есть неизвестный мне массив, я должен сканировать все типы во всех сборках, загруженных в приложение, и для каждого я должен вычислять эти 8 байтов, пока не найду тот же массив.
Я не знаю другого способа найти тип, поэтому я пытаюсь максимально ускорить его.

Ответы [ 3 ]

4 голосов
/ 17 июля 2009

Автор ссылки на статью здесь.

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

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

Stack<Byte[]> _byteStack = new Stack<Byte[]>();

Byte[] AllocateArray()
{
Byte[] outArray;
if (_byteStack.Count > 0)
  outArray = _byteStack.Pop(); 
else
  outArray = new Byte[8];
return outArray;
}

void RecycleArray(Byte[] inArray)
{
  _byteStack.Push(inArray);
}

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

2 голосов
/ 14 июля 2009

с вашей линии:

У меня есть код, который работает на многих маленьких байтовых массивах (длиной 8-10 байт)

Лично меня больше интересовало бы размещение запасного буфера где-нибудь, что различные части вашего кода могут использовать повторно (при обработке одного и того же блока). Тогда вам не о чем беспокоиться. В большинстве случаев (когда буфер используется для очень осторожных операций) с чистым буфером, вы даже можете всегда предполагать, что это «все ваше» - то есть каждый метод, который нуждается в нем, может предполагать, что они могут начать запись с нуля.

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

1 голос
/ 14 июля 2009

System.Array (класс, представляющий массив) является ссылочным типом и находится в куче. Вы можете иметь массив только в стеке, если используете небезопасный код.

Я не вижу, где говорится в статье, на которую вы ссылаетесь. Если вы хотите иметь массив, выделенный стеком, вы можете сделать что-то вроде этого:

decimal* stackAllocatedDecimals = stackalloc decimal[4];

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

Эта статья CodeProject может быть полезна для вас.

...