Топ Вопросов о Памяти в .NET. Продолжение 25-27
Начало 1-4
Продолжение 5-8
Продолжение 9-12
Продолжение 13-16
Продолжение 17-20
Продолжение 21-24
25. Что такое интернирование строк?
Интернирование строк - это метод, позволяющий не дублировать экземпляры строк с одинаковым значением, известным во время компиляции. Таким образом, каждый раз, когда вы используете строковый литерал вроде
"Hello world!" в разных местах вашего кода C# (в одном проекте/сборке) компилятор распознает это и будет рассматривать как одну «интернированную строку». Такие интернированные строки - это обычные строки, размещённые в управляемой куче. Единственное отличие состоит в том, что JIT знает о них, поэтому при компиляции IL кода, ссылающегося на них, он будет повторно использовать уже выделенную строку вместо создания новой с тем же значением. «Пул Интернированных Строк» (String Intern Pool) - это пул для обработки адресов/экземпляров этих строк, а не какое-либо выделенное пространство для них.Дедупликация динамически создаваемых строк (со значением, неизвестным во время компиляции) не использует пул, потому что накладные расходы на проверку того, существует ли уже строка с заданным значением, вероятно, сократят преимущество от невыделения новой строки. В настоящее время открыт вопрос о дедупликации строк в фоновом режиме, но она пока не реализована.
Существует потокобезопасный API, с помощью которого вы можете получить доступ к пулу строк, чтобы проверить, интернирована ли строка с заданным значением (
string.IsInterned) или принудительно интернировать её (string.Intern).26. Какие аллокации происходят в следующем методе:
IEnumerable Processing(List input) =>LINQ - это очень удобный высокоуровневый способ написания декларативного кода. Однако он не оптимизирован для высокопроизводительных горячих путей в вашем коде. Многие операции что-то выделяют в куче, как и в этом случае. Каждый раз, когда вы используете
input
.Where(static x => x > 0)
.Select(static x => x * x);
Where или Select, выделяется специальный класс-итератор. Он может комбинироваться с другими. В нашем случае сначала выделяется WhereListIterator (из-за вызова Where), а затем он объединяется в WhereSelectListIterator (из-за вызова Select). Оба экземпляра занимают 152 байта, что явно не так много, если рассматривать один вызов. Но если он используется в горячем пути и вызывается тысячи или миллионы раз, и вы получите мегабайты мусора только из-за этой единственной строчки кода.Каждая лямбда также выделяет экземпляр
Func, но обычно они оптимизируются с помощью кеширования. То есть, хотя первый вызов действительно выделит два экземпляра Func для представления лямбда-выражений в методах Where и Select, они будут повторно использоваться в последующих вызовах.Примечание: статические лямбда-функции – нововведение в C#9.
27. Приводит ли ToString() на структуре к боксингу?
ToString() у структур имеет реализацию по умолчанию и вызывает боксинг структуры (размещение её в управляемой куче). Если вы хотите избежать ненужного боксинга, вам необходимо переопределить метод ToString().Окончание следует…
Источник: https://dotnetmemoryexpert.com