По соображениям производительности памяти у меня есть массив структур, так как количество элементов велико, и элементы регулярно подбрасываются и, следовательно, измельчают кучу GC. Это не вопрос о том, следует ли использовать большие структуры; Я уже определил, что перехват GC вызывает проблемы с производительностью. Мой вопрос в том, когда мне нужно обработать этот массив структур, не следует ли мне использовать LINQ? Поскольку структура невелика, нецелесообразно передавать ее по значению, и я понятия не имею, если генератор кода LINQ достаточно умен, чтобы это сделать или нет. Структура выглядит следующим образом:
public struct ManufacturerValue
{
public int ManufacturerID;
public string Name;
public string CustomSlug;
public string Title;
public string Description;
public string Image;
public string SearchFilters;
public int TopZoneProduction;
public int TopZoneTesting;
public int ActiveProducts;
}
Итак, скажем, у нас есть массив этих значений, и я хочу извлечь словарь пользовательских слизней для идентификаторов производителей. Прежде чем я изменил это на структуру, это был класс, поэтому исходный код был написан простым запросом LINQ:
ManufacturerValue[] = GetManufacturerValues();
var dict = values.Where(p => !string.IsNullOrEmpty(p.CustomSlug))
.ToDictionary(p => p.CustomSlug, p => p.ManufacturerID);
Моя забота - я хочу понять, как LINQ собирается генерировать фактический код для создания этого словаря. Мое подозрение состоит в том, что внутри код LINQ будет иметь нечто вроде этой наивной реализации:
var dict = new Dictionary<string, int>();
for (var i = 0; i < values.Length; i++) {
var value = values[i];
if (!string.IsNullOrEmpty(value.CustomSlug)) {
dict.Add(value.CustomSlug, value.ManufacturerID);
}
}
что было бы плохо, потому что третья строка создаст локальную копию структуры, которая будет медленной, потому что структура большая и вместо этого будет разбивать шину памяти. Нам также не нужно ничего, кроме идентификатора и пользовательского пули, чтобы он копировал много бесполезной информации на каждой итерации. Скорее, если бы я сам его правильно закодировал, я бы написал его так:
var dict = new Dictionary<string, int>();
for (var i = 0; i < values.Length; i++) {
if (!string.IsNullOrEmpty(values[i].CustomSlug)) {
dict.Add(values[i].CustomSlug, values[i].ManufacturerID);
}
}
Знает ли кто-нибудь, если генератор кода достаточно умен, чтобы использовать простое индексирование массива, как второй пример, когда код генератора запускается над массивами структур или он реализует более наивную, но медленную первую реализацию?
Каков наилучший способ декомпилировать этот тип кода, чтобы узнать, что на самом деле сделает этот генератор кода?
UPDATE
Эти изменения теперь производятся. Как оказалось, в процессе перезаписи кода и использования профилировщика Dot Memory для определения того, сколько памяти было использовано, и где я обнаружил две утечки памяти в коде компилятора Phalanger PHP. Это была одна из причин того, что объем памяти, которую использовали наши процессы, продолжал расти, и одна из утечек памяти была действительно неприятной и фактически вызвана кодом Microsoft Async (вероятно, стоит вопрос или вопрос о переполнении блога, чтобы помочь другим избежать она).
Во всяком случае, как только я обнаружил утечку памяти и исправил ее, я нажал этот код без каких-либо оптимизаций памяти для преобразования из классов в структуры, и, как ни странно, это на самом деле заставило GC трэш даже больше. Я видел периоды времени, когда GC будет использовать до 27% процессора в соответствии с счетчиками производительности. Скорее всего, эти большие блоки ранее не получали GC'ed из-за утечек памяти, поэтому они просто зависали. Как только код был исправлен, GC начал вести себя еще хуже, чем раньше.
Наконец, мы закончили код для преобразования этих классов в структуры с использованием обратной связи в этом вопросе, и теперь наше общее использование памяти на пике составляет около 50% того, что было, оно быстро падает, когда загрузка на сервере идет и, что еще важнее, мы видим, что только 0,05% процессора используется для GC, если даже это. Поэтому, если кто-то задается вопросом, могут ли эти изменения повлиять на реальный мир, они действительно могут, особенно если у вас есть объекты, которые обычно висят на некоторое время, так что застряли в куче второго поколения, а затем нужно получить бросок и сбор мусора.