День восемьсот четырнадцатый. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Начало 1-4
Вчера в нашем чате поделились интересной ссылкой на тест по организации памяти в .NET. Кому интересно попробовать свои силы перед тем, как читать дальше - https://quiz.dotnetmemoryexpert.com/
1. Что чаще всего вызывает сборку мусора в приложении .NET?
Наиболее распространённой причиной является случай, когда вы выделяете объект, и (грубо говоря) для него не хватает места. Таким образом, если приложение не выделяет новых объектов, есть небольшая вероятность, что сборки мусора вообще произойдёт. Вот почему вы могли слышать о zero-allocation коде. Такой код имеет хорошую производительность не только потому, что он не использует аллокации, но также значительно снижает вероятность сборки мусора и связанных с этим накладных расходов. А знать о том, когда происходит выделение памяти и избегать ненужных выделений - один из наиболее важных навыков при написании требовательного к памяти и производительности кода.
Другой, менее распространенный триггер сборки мусора - когда операционная система замечает нехватку доступной памяти. Она передаёт так называемое «уведомление о нехватке памяти», и различные программы могут реагировать на него (или игнорировать его). Среда выполнения .NET реагирует запуском сборки мусора, а также переключением в «режим низкого потребления памяти», что приводит к более агрессивному освобождению памяти.
Очевидно, что вызов
2. В .NET 5 и Blazor (WebAssembly) одинаковые алгоритмы сборки мусора?
Blazor WebAssembly, начиная с .NET 5, работает на Mono (изначально написанном на C), но компилируется в WebAssembly. Таким образом, поскольку среда выполнения совершенно другая, она имеет и другой сборщик мусора. Хотя в будущем всё может измениться, потому что Mono интенсивно развивается и активно экспериментирует (например, в использовании «основного сборщика мусора» .NET).
3. Что означает так называемая «полная» сборка мусора?
При полной сборке мусора сборщик обрабатывает все поколения в SOH, а также LOH и POH (добавленной в .NET 5). Поэтому такую сборку следует воспринимать как самую «дорогую» с точки зрения загрузки памяти и процессора. В хорошо работающем приложении это должно происходить заметно реже, чем сборка в поколениях 0 и 1.
В настоящее время существует 2 варианта полной сборки мусора: параллельная и уплотняющая. Может выполняться один из вариантов, но не оба вместе. Параллельная (или фоновая) является наиболее распространённой и предпочтительной, поскольку приводит к коротким паузам, что не сильно влияет на поведение приложения. Но память при этом не сжимается, что приводит к фрагментации: свободному пространству, которое не всегда можно использовать повторно. Если фрагментация станет сильной, может начаться уплотняющая полная сборка мусора, которая может привести к длительным паузам в работе приложение. В противном случае процесс будет потреблять всё больше и больше памяти.
4. Что такое «кризис среднего возраста»?
Под «кризисом среднего возраста» мы понимаем нарушение так называемых гипотез поколений, на которых построены все «поколенческие» сборщики мусора (в том числе и .NET). Они подразумевают, что большинство объектов умирают молодыми, и что существует небольшая группа объектов, живущих долго. «Если объект молодой, он, вероятно, скоро умрёт. Если он живет долго, он, вероятно, проживет ещё дольше».
Поэтому объект, живущий достаточно долго, чтобы считаться «старым», а затем умирающий, нарушает это правило. Это негативно влияет на поведение сборщика мусора, которое настроено на противоположное поведение: чаще собирать мусор в молодых поколениях и реже в старых. «Кризис среднего возраста» - одна из наиболее распространённых проблем с памятью .NET, которая вызывает более высокую загрузку процессора и паузы.
Продолжение следует...
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Начало 1-4
Вчера в нашем чате поделились интересной ссылкой на тест по организации памяти в .NET. Кому интересно попробовать свои силы перед тем, как читать дальше - https://quiz.dotnetmemoryexpert.com/
1. Что чаще всего вызывает сборку мусора в приложении .NET?
Наиболее распространённой причиной является случай, когда вы выделяете объект, и (грубо говоря) для него не хватает места. Таким образом, если приложение не выделяет новых объектов, есть небольшая вероятность, что сборки мусора вообще произойдёт. Вот почему вы могли слышать о zero-allocation коде. Такой код имеет хорошую производительность не только потому, что он не использует аллокации, но также значительно снижает вероятность сборки мусора и связанных с этим накладных расходов. А знать о том, когда происходит выделение памяти и избегать ненужных выделений - один из наиболее важных навыков при написании требовательного к памяти и производительности кода.
Другой, менее распространенный триггер сборки мусора - когда операционная система замечает нехватку доступной памяти. Она передаёт так называемое «уведомление о нехватке памяти», и различные программы могут реагировать на него (или игнорировать его). Среда выполнения .NET реагирует запуском сборки мусора, а также переключением в «режим низкого потребления памяти», что приводит к более агрессивному освобождению памяти.
Очевидно, что вызов
GC.Collect может (или не может, в зависимости от его параметров) запускать сборку мусора. Но такие вызовы довольно редки, как и другие, менее распространённые триггеры.2. В .NET 5 и Blazor (WebAssembly) одинаковые алгоритмы сборки мусора?
Blazor WebAssembly, начиная с .NET 5, работает на Mono (изначально написанном на C), но компилируется в WebAssembly. Таким образом, поскольку среда выполнения совершенно другая, она имеет и другой сборщик мусора. Хотя в будущем всё может измениться, потому что Mono интенсивно развивается и активно экспериментирует (например, в использовании «основного сборщика мусора» .NET).
3. Что означает так называемая «полная» сборка мусора?
При полной сборке мусора сборщик обрабатывает все поколения в SOH, а также LOH и POH (добавленной в .NET 5). Поэтому такую сборку следует воспринимать как самую «дорогую» с точки зрения загрузки памяти и процессора. В хорошо работающем приложении это должно происходить заметно реже, чем сборка в поколениях 0 и 1.
В настоящее время существует 2 варианта полной сборки мусора: параллельная и уплотняющая. Может выполняться один из вариантов, но не оба вместе. Параллельная (или фоновая) является наиболее распространённой и предпочтительной, поскольку приводит к коротким паузам, что не сильно влияет на поведение приложения. Но память при этом не сжимается, что приводит к фрагментации: свободному пространству, которое не всегда можно использовать повторно. Если фрагментация станет сильной, может начаться уплотняющая полная сборка мусора, которая может привести к длительным паузам в работе приложение. В противном случае процесс будет потреблять всё больше и больше памяти.
4. Что такое «кризис среднего возраста»?
Под «кризисом среднего возраста» мы понимаем нарушение так называемых гипотез поколений, на которых построены все «поколенческие» сборщики мусора (в том числе и .NET). Они подразумевают, что большинство объектов умирают молодыми, и что существует небольшая группа объектов, живущих долго. «Если объект молодой, он, вероятно, скоро умрёт. Если он живет долго, он, вероятно, проживет ещё дольше».
Поэтому объект, живущий достаточно долго, чтобы считаться «старым», а затем умирающий, нарушает это правило. Это негативно влияет на поведение сборщика мусора, которое настроено на противоположное поведение: чаще собирать мусор в молодых поколениях и реже в старых. «Кризис среднего возраста» - одна из наиболее распространённых проблем с памятью .NET, которая вызывает более высокую загрузку процессора и паузы.
Продолжение следует...
Источник: https://dotnetmemoryexpert.com
День восемьсот двадцатый. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Продолжение 5-8
Начало 1-4
5. Какие ограничения на размер занимаемой памяти у приложений .NET?
Ограничения размера приложения .NET такие же, как у любого процесса, ограниченного виртуальным адресным пространством - объемом памяти, который может быть выделен, исходя из разрядности приложения. И хотя в настоящее время подавляющее большинство операционных систем являются 64-битными, мы всё ещё можем компилировать/запускать наши программы и как 32-, и как 64-битные. То же самое относится к среде выполнения .NET, выполняющей наше приложение .NET. См. также про 64-битную VS 2022.
32-битному приложению может быть выделено до 4 ГБ памяти, но по умолчанию половина его предназначена для операционной системы Windows, а половина - для самого приложения. Таким образом, ограничение по умолчанию составляет 2 ГБ. Однако в случае 64-битной Windows мы можем запускать 32-битные приложения в так называемом режиме обработки больших адресов (Large Address Aware), который позволяет выделять больше памяти - около 3 ГБ. Этот флаг, например, используется при размещении 32-разрядных приложений ASP.NET Framework внутри IIS. В Linux действуют аналогичные ограничения. Таким образом, около 2 или 3 ГБ - это предел для 32-разрядного приложения .NET.
64-битному приложению теоретически можно выделить до 16 ЭБ (эксабайт!) памяти. В настоящее время большая часть оборудования использует только 48 бит для выделения верхних и нижних 128 ТБ всего адресного пространства (для операционной системы и приложения). Это предел для приложений .NET.
6. Что такое LOH (Large Object Heap)?
Куча больших объектов - это специальная часть управляемой кучи. С самого начала .NET порог по умолчанию для обработки объекта как «большого» составляет 85000 байт. Недавно добавилась возможность увеличить этот лимит. Каждый большой объект выделяется в LOH и остаётся там до тех пор, пока не будет собран мусор.
LOH отделён от SOH (Small Objects Heap – кучи малых объектов), потому что «большие» объекты имеют другие характеристики: их создание и перемещение (сжатие) памяти может повлечь за собой большие накладные расходы. Поскольку ожидается, что таких объектов будет немного, затраты на их размещение выше (включая очистку памяти и некоторые накладные расходы на многопоточную синхронизацию). Т.к. нет другого способа очистки LOH, кроме полной сборки мусора, если ваше приложение часто размещает большие объекты и приводит к нехватке памяти, оно может приводить к дорогостоящим полным сборкам мусора.
7. Для чего нужна утилита dotnet trace?
-
-
-
8. Для чего нужна утилита dotnet gcdump?
Продолжение следует…
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Продолжение 5-8
Начало 1-4
5. Какие ограничения на размер занимаемой памяти у приложений .NET?
Ограничения размера приложения .NET такие же, как у любого процесса, ограниченного виртуальным адресным пространством - объемом памяти, который может быть выделен, исходя из разрядности приложения. И хотя в настоящее время подавляющее большинство операционных систем являются 64-битными, мы всё ещё можем компилировать/запускать наши программы и как 32-, и как 64-битные. То же самое относится к среде выполнения .NET, выполняющей наше приложение .NET. См. также про 64-битную VS 2022.
32-битному приложению может быть выделено до 4 ГБ памяти, но по умолчанию половина его предназначена для операционной системы Windows, а половина - для самого приложения. Таким образом, ограничение по умолчанию составляет 2 ГБ. Однако в случае 64-битной Windows мы можем запускать 32-битные приложения в так называемом режиме обработки больших адресов (Large Address Aware), который позволяет выделять больше памяти - около 3 ГБ. Этот флаг, например, используется при размещении 32-разрядных приложений ASP.NET Framework внутри IIS. В Linux действуют аналогичные ограничения. Таким образом, около 2 или 3 ГБ - это предел для 32-разрядного приложения .NET.
64-битному приложению теоретически можно выделить до 16 ЭБ (эксабайт!) памяти. В настоящее время большая часть оборудования использует только 48 бит для выделения верхних и нижних 128 ТБ всего адресного пространства (для операционной системы и приложения). Это предел для приложений .NET.
6. Что такое LOH (Large Object Heap)?
Куча больших объектов - это специальная часть управляемой кучи. С самого начала .NET порог по умолчанию для обработки объекта как «большого» составляет 85000 байт. Недавно добавилась возможность увеличить этот лимит. Каждый большой объект выделяется в LOH и остаётся там до тех пор, пока не будет собран мусор.
LOH отделён от SOH (Small Objects Heap – кучи малых объектов), потому что «большие» объекты имеют другие характеристики: их создание и перемещение (сжатие) памяти может повлечь за собой большие накладные расходы. Поскольку ожидается, что таких объектов будет немного, затраты на их размещение выше (включая очистку памяти и некоторые накладные расходы на многопоточную синхронизацию). Т.к. нет другого способа очистки LOH, кроме полной сборки мусора, если ваше приложение часто размещает большие объекты и приводит к нехватке памяти, оно может приводить к дорогостоящим полным сборкам мусора.
7. Для чего нужна утилита dotnet trace?
dotnet trace - это один из инструментов командной строки (CLI) для сбора различных «диагностических трассировок» процесса .NET. Вы можете использовать три предопределенных профиля:-
cpu-sampling - выборка профилировщика CPU для наблюдения за использованием процессора,-
gc-collect - отслеживание высокоуровневых данных сборщика мусора с очень низкими накладными расходами,-
gc-verbose – то же, что выше, плюс грубая выборка распределения объектов. Созданная трассировка может быть затем открыта в Visual Studio или в инструменте PerfView.8. Для чего нужна утилита dotnet gcdump?
dotnet gcdump - еще один инструмент диагностики, который может запускать сборщик мусора и записывать специальные диагностические данные, выдаваемые во время него. Это позволяет создавать «gcdump» - не обычный дамп памяти, содержащий всю или часть памяти процесса, а «диагностический снимок» состояния управляемой памяти. Он включает информацию о том, какие управляемые объекты были обнаружены и собраны во время сборки мусора (без содержания этих объектов). Поэтому «gcdump» намного меньше, чем снимок всей памяти, потребляемой процессом. Его можно проанализировать в Visual Studio или PerfView (включая информацию об отношениях между объектами).Продолжение следует…
Источник: https://dotnetmemoryexpert.com
День восемьсот двадцать шестой. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Продолжение 9-12
Начало 1-4
Продолжение 5-8
9. Что обязательно будет содержать дамп памяти любого приложения .NET?
Забавный факт, который иногда может вводить в заблуждение при анализе дампов памяти: каждый процесс .NET заведомо выделяет экземпляры
Кроме того, некоторые массивы
10. Что означает выражение "stop the world" в контексте сборки мусора?
Каждый запуск сборки мусора в .NET имеет несколько коротких и длинных фаз, когда ожидается, что среда выполнения «приостановит» приложение. Эти паузы также известны как фазы «остановки мира» ("stop the world"). И в целом они явно нежелательны, так как влияют на скорость отклика и производительность приложения. Многие улучшения .NET GC делают эти паузы как можно короче.
Итак, «остановка мира» - это пауза на время выполнения сборки мусора (или её части), когда все управляемые потоки «приостановлены». Например, это позволяет получить единообразное представление о том, какие управляемые объекты используются. Неуправляемые потоки не приостанавливаются, поскольку в этом нет необходимости - по умолчанию они не обращаются к управляемым объектам, и даже если это так, они обращаются к «закреплённым» (pinned) объектам, которые обрабатываются особым образом.
11. Как работает параллельная сборка мусора в .NET 5?
Параллельная (фоновая) сборка мусора большую часть времени работает одновременно с управляемыми потоками, не создавая длительных пауз для «остановки мира». Это не означает, что пауз вообще не бывает. Требуется как минимум две паузы: в начале и где-то посередине, чтобы получить некоторое согласованное представление о состоянии памяти.
Более того, текущая реализация .NET GC не может сжимать память во время работы приложения. Таким образом, как полная сборка мусора, так и сборка в поколениях 0 и 1, должны работать в режиме «остановки мира», если требуется сжать память.
Работа над внедрением параллельного сжатия памяти определённо продолжается, и рано или поздно мы можем ожидать его добавления в экосистему .NET. Такие реализации успешно используются, например, в экосистеме JVM. Тем не менее, у них есть свои недостатки и компромиссы, поскольку ничего не даётся бесплатно.
12. Как параметры нужно учитывать, чтобы оценить потребление памяти вашей программой?
Чтобы иметь хорошее общее представление о потреблении памяти вашей .NET-программой, лучше всего знать как минимум три величины.
1. Сколько памяти выделено вашей программе в целом (частные байты - private bytes).
2. Сколько её физически потребляется в RAM («рабочий набор» - working set) - это позволит заметить случаи, когда страницы памяти выгружаются на диск.
3. В контексте .NET полезно знать, сколько памяти потребляется в управляемой куче (Managed Heap).
Что же касается виртуального адресного пространства (virtual address space), оно охватывает всё адресное пространство, которое может использоваться нашим приложением, и не связано напрямую с поведением приложения.
Продолжение следует…
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Продолжение 9-12
Начало 1-4
Продолжение 5-8
9. Что обязательно будет содержать дамп памяти любого приложения .NET?
Забавный факт, который иногда может вводить в заблуждение при анализе дампов памяти: каждый процесс .NET заведомо выделяет экземпляры
OutOfMemoryException и StackOverflowException. Просто на случай, если они понадобятся, что будет означать действительную нехватку памяти и отсутствие возможности их создать!Кроме того, некоторые массивы
object[] предварительно выделяются в LOH для ссылок на объекты, используемые «дескрипторами». Это важный механизм, используемый интернированием строк, статикой и локальной статикой потока. Так, например, даже если вы вообще не используете LOH, вы увидите там несколько массивов, ссылающихся на ваши статические объекты.10. Что означает выражение "stop the world" в контексте сборки мусора?
Каждый запуск сборки мусора в .NET имеет несколько коротких и длинных фаз, когда ожидается, что среда выполнения «приостановит» приложение. Эти паузы также известны как фазы «остановки мира» ("stop the world"). И в целом они явно нежелательны, так как влияют на скорость отклика и производительность приложения. Многие улучшения .NET GC делают эти паузы как можно короче.
Итак, «остановка мира» - это пауза на время выполнения сборки мусора (или её части), когда все управляемые потоки «приостановлены». Например, это позволяет получить единообразное представление о том, какие управляемые объекты используются. Неуправляемые потоки не приостанавливаются, поскольку в этом нет необходимости - по умолчанию они не обращаются к управляемым объектам, и даже если это так, они обращаются к «закреплённым» (pinned) объектам, которые обрабатываются особым образом.
11. Как работает параллельная сборка мусора в .NET 5?
Параллельная (фоновая) сборка мусора большую часть времени работает одновременно с управляемыми потоками, не создавая длительных пауз для «остановки мира». Это не означает, что пауз вообще не бывает. Требуется как минимум две паузы: в начале и где-то посередине, чтобы получить некоторое согласованное представление о состоянии памяти.
Более того, текущая реализация .NET GC не может сжимать память во время работы приложения. Таким образом, как полная сборка мусора, так и сборка в поколениях 0 и 1, должны работать в режиме «остановки мира», если требуется сжать память.
Работа над внедрением параллельного сжатия памяти определённо продолжается, и рано или поздно мы можем ожидать его добавления в экосистему .NET. Такие реализации успешно используются, например, в экосистеме JVM. Тем не менее, у них есть свои недостатки и компромиссы, поскольку ничего не даётся бесплатно.
12. Как параметры нужно учитывать, чтобы оценить потребление памяти вашей программой?
Чтобы иметь хорошее общее представление о потреблении памяти вашей .NET-программой, лучше всего знать как минимум три величины.
1. Сколько памяти выделено вашей программе в целом (частные байты - private bytes).
2. Сколько её физически потребляется в RAM («рабочий набор» - working set) - это позволит заметить случаи, когда страницы памяти выгружаются на диск.
3. В контексте .NET полезно знать, сколько памяти потребляется в управляемой куче (Managed Heap).
Что же касается виртуального адресного пространства (virtual address space), оно охватывает всё адресное пространство, которое может использоваться нашим приложением, и не связано напрямую с поведением приложения.
Продолжение следует…
Источник: https://dotnetmemoryexpert.com
День восемьсот тридцатый. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Продолжение 13-16
Начало 1-4
Продолжение 5-8
Продолжение 9-12
13. Что такое POH?
Куча закреплённых объектов (Pinned Object Heap) - это новый тип раздела управляемой кучи (помимо SOH и LOH), добавленный в .NET 5 и предназначенный для объектов, которые не будут перемещаться сборщиком мусора. Таким образом, POH никогда не уплотняется, что позволяет рассматривать все объекты в POH как «закреплённые» по умолчанию. Это полезно, потому что закрепление в SOH/LOH вводит некоторые накладные расходы и снижает гибкость сжатия памяти (что может привести к фрагментации). Наличие специального места для «закреплённых» объектов устраняет эту проблему.
Однако для аллокаций памяти был добавлен новый API, потому что теперь нам нужно указать, что мы выделяем объект, который необходимо немедленно закрепить. В настоящее время это можно сделать с помощью
14. Какую сборку мусора мы можем вызвать через API GC?
В .NET доступны API, позволяющие контролировать поведение сборщика мусора. Например,
С другой стороны, действительно есть возможность запустить сжатие LOH при следующей непараллельной полной сборке мусора вот таким способом:
Когда мы запускаем приложение .NET, оно выполняется средой выполнения .NET внутри обособленного процесса. Другими словами, каждое приложение .NET выполняется своим собственным экземпляром среды выполнения, и между ними нет ничего общего. Это позволяет нам настраивать и управлять жизненным циклом каждого приложения .NET отдельно. Это касается и сборщика мусора, и управляемой кучи. Каждый процесс имеет свой собственные кучу и сборщик мусора и не знает о существовании других. Сборщик мусора, запускаемый в одном приложении .NET, не влияет (и не запускает) сборщик мусора в другом приложении .NET.
При этом процессы, запущенные на одном компьютере, совместно используют некоторые ресурсы, такие как ЦП, память и диски. Очевидно, что на этом уровне может произойти некоторое совместное использование ресурсов.
16. Каково предназначение флага gcAllowVeryLargeObjects?
Если вы когда-либо достигали предела общего размера объекта в 2Гб - возможно, массива или строки, хорошей новостью для вас является то, что вы можете преодолеть это ограничение с помощью флага
Продолжение следует…
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Продолжение 13-16
Начало 1-4
Продолжение 5-8
Продолжение 9-12
13. Что такое POH?
Куча закреплённых объектов (Pinned Object Heap) - это новый тип раздела управляемой кучи (помимо SOH и LOH), добавленный в .NET 5 и предназначенный для объектов, которые не будут перемещаться сборщиком мусора. Таким образом, POH никогда не уплотняется, что позволяет рассматривать все объекты в POH как «закреплённые» по умолчанию. Это полезно, потому что закрепление в SOH/LOH вводит некоторые накладные расходы и снижает гибкость сжатия памяти (что может привести к фрагментации). Наличие специального места для «закреплённых» объектов устраняет эту проблему.
Однако для аллокаций памяти был добавлен новый API, потому что теперь нам нужно указать, что мы выделяем объект, который необходимо немедленно закрепить. В настоящее время это можно сделать с помощью
GC.AllocateUninitializedArray. То есть мы можем выделить там только массив типов, которые не являются ссылочными и не содержат ссылок (например, массив байтов). Хотя собственно POH не имеет таких ограничений.14. Какую сборку мусора мы можем вызвать через API GC?
В .NET доступны API, позволяющие контролировать поведение сборщика мусора. Например,
GC.Collect и его перегрузки позволяют нам запускать сборку мусора в поколениях 0, 1 или полную (с указанием, хотите ли вы, чтобы она была блокирующей и/или с уплотнением памяти). Однако из-за того, как работает сборка мусора в .NET, мы не можем запустить сборку только поколения 2 или только LOH. При сборке поколения (или LOH) всегда выполняется сборка мусора для всех младших поколений. Поэтому, когда мы запускаем сборку в поколении 2, мы запускаем полную сборку мусора. И нет API для запуска только сборки в LOH (в этом случае также будет запущена полная сборка).С другой стороны, действительно есть возможность запустить сжатие LOH при следующей непараллельной полной сборке мусора вот таким способом:
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;15. Используются ли память и сборщик мусора разными .NET приложениями совместно?
GC.Collect();
Когда мы запускаем приложение .NET, оно выполняется средой выполнения .NET внутри обособленного процесса. Другими словами, каждое приложение .NET выполняется своим собственным экземпляром среды выполнения, и между ними нет ничего общего. Это позволяет нам настраивать и управлять жизненным циклом каждого приложения .NET отдельно. Это касается и сборщика мусора, и управляемой кучи. Каждый процесс имеет свой собственные кучу и сборщик мусора и не знает о существовании других. Сборщик мусора, запускаемый в одном приложении .NET, не влияет (и не запускает) сборщик мусора в другом приложении .NET.
При этом процессы, запущенные на одном компьютере, совместно используют некоторые ресурсы, такие как ЦП, память и диски. Очевидно, что на этом уровне может произойти некоторое совместное использование ресурсов.
16. Каково предназначение флага gcAllowVeryLargeObjects?
Если вы когда-либо достигали предела общего размера объекта в 2Гб - возможно, массива или строки, хорошей новостью для вас является то, что вы можете преодолеть это ограничение с помощью флага
gcAllowVeryLargeObjects (по умолчанию отключен). Он позволяет создавать массивы размером более 2Гб, но применим только к массивам (то есть не применим к строкам или другим типам объектов) и только к общему размеру массива. Максимальное количество элементов в массиве (UInt32.MaxValue) не меняется. И хотя это, конечно, не самое распространённое требование, например, оно может быть полезно в приложениях, обрабатывающих огромные изображения или большие данные.Продолжение следует…
Источник: https://dotnetmemoryexpert.com
День восемьсот тридцать пятый. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Продолжение 17-20
Начало 1-4
Продолжение 5-8
Продолжение 9-12
Продолжение 13-16
17. Зачем классу финализатор?
Финализатор - это специальный метод, который вызывается средой выполнения после того, как объект будет помечен как недостижимый. Другими словами, это специальный метод, вызываемый перед сборкой мусора. Таким образом, он рассматривается как подстраховка для высвобождения некоторых неуправляемых ресурсов для объектов, содержащих их. Обычно это какой-нибудь «дескриптор» файла, сокета или что-то подобное. Предпочтительным способом является использование контракта
Заметьте, что
- точное время, когда именно будет вызван финализатор, не определено.
- порядок вызова финализаторов в объектах (даже связанных друг с другом) не гарантируется.
18. Можно ли узнать о сборке мусора или управлять ей?
К сожалению, в настоящее время нет доступного API, который будет информировать о происходящей в данный момент сборке мусора. Более того, нет даже надёжного API, который предупредит нас о грядущей сборке. Существует метод
С другой стороны, есть метод
19. Зачем используется управляемый указатель (ref)?
Управляемый указатель (также известный как
Управляемый указатель довольно часто используется в низкоуровневом производительном коде для непосредственного управления данными, особенно в сочетании со структурами и/или объектами
20. Чем отличается серверная сборка мусора?
Серверная сборка мусора - это режим, предназначенный для приложений с одновременной обработкой запросов, как правило, веб-приложений. Но её с успехом можно использовать и в любом другом типе приложений с аналогичными характеристиками (например, сервисом, обрабатывающим сообщения из очереди). То есть в приложениях, где нас больше всего волнует пропускная способность - обработка как можно большего количества запросов в секунду. Таким образом, в отличие от сборки мусора в режиме рабочей станции, серверная не так сильно озабочена паузами (задержкой), потому что нет прямого пользователя (например, взаимодействующего с пользовательским интерфейсом), на которого они повлияют.
И поскольку мы предполагаем, что приложение «серверное», оно также более охотно потребляет память и потоки ЦП для достижения своих целей.
Продолжение следует…
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Продолжение 17-20
Начало 1-4
Продолжение 5-8
Продолжение 9-12
Продолжение 13-16
17. Зачем классу финализатор?
Финализатор - это специальный метод, который вызывается средой выполнения после того, как объект будет помечен как недостижимый. Другими словами, это специальный метод, вызываемый перед сборкой мусора. Таким образом, он рассматривается как подстраховка для высвобождения некоторых неуправляемых ресурсов для объектов, содержащих их. Обычно это какой-нибудь «дескриптор» файла, сокета или что-то подобное. Предпочтительным способом является использование контракта
IDisposable и освобождение этих ресурсов путем явного вызова Dispose (или с помощью директивы using). Но если программист забудет это сделать, финализатор придёт на помощь. Таким образом, классу может потребоваться финализатор, чтобы убедиться, что неуправляемый ресурс, которым он владеет, будет очищен. Финализатор, хотя обычно используется вместе с IDisposable, никак не связан с ним. Заметьте, что
- точное время, когда именно будет вызван финализатор, не определено.
- порядок вызова финализаторов в объектах (даже связанных друг с другом) не гарантируется.
18. Можно ли узнать о сборке мусора или управлять ей?
К сожалению, в настоящее время нет доступного API, который будет информировать о происходящей в данный момент сборке мусора. Более того, нет даже надёжного API, который предупредит нас о грядущей сборке. Существует метод
GC.RegisterForFullGCNotification, который (как сказано в документации) выдаёт уведомление, «когда среда выполнения чувствует, что приближается полная сборка мусора». Но это «чувство» не является точным и также зависит от магического порога, который придётся тонко настроить в соответствии с рабочей нагрузкой вашего приложения методом проб и ошибок. Этот метод не рекомендуется использовать.С другой стороны, есть метод
GC.Collect для запуска сборки мусора и менее известный метод GC.TryStartNoGCRegion, чтобы попытаться отключить сборку мусора на заданное количество аллокаций памяти.19. Зачем используется управляемый указатель (ref)?
Управляемый указатель (также известный как
ref или byref) - это особый тип указателя на разные места в памяти: данные стека, внутренние объекты или массивы или неуправляемые данные. И поскольку он может указывать на данные стека, есть серьёзные ограничения на то, где мы можем его использовать. Например, в настоящее время запрещено использовать его в качестве поля класса, потому что он может прожить дольше, чем адрес в стеке, на который он указывает. Запрещено даже использовать его в качестве поля структуры (всегда живущей в стеке), хотя это ограничение может быть ослаблено в будущем.Управляемый указатель довольно часто используется в низкоуровневом производительном коде для непосредственного управления данными, особенно в сочетании со структурами и/или объектами
Span<T> (которые, кстати, под капотом также используют управляемые указатели).20. Чем отличается серверная сборка мусора?
Серверная сборка мусора - это режим, предназначенный для приложений с одновременной обработкой запросов, как правило, веб-приложений. Но её с успехом можно использовать и в любом другом типе приложений с аналогичными характеристиками (например, сервисом, обрабатывающим сообщения из очереди). То есть в приложениях, где нас больше всего волнует пропускная способность - обработка как можно большего количества запросов в секунду. Таким образом, в отличие от сборки мусора в режиме рабочей станции, серверная не так сильно озабочена паузами (задержкой), потому что нет прямого пользователя (например, взаимодействующего с пользовательским интерфейсом), на которого они повлияют.
И поскольку мы предполагаем, что приложение «серверное», оно также более охотно потребляет память и потоки ЦП для достижения своих целей.
Продолжение следует…
Источник: https://dotnetmemoryexpert.com
День восемьсот тридцать девятый. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Продолжение 21-24
Начало 1-4
Продолжение 5-8
Продолжение 9-12
Продолжение 13-16
Продолжение 17-20
21. Как измерить время паузы на сборку мусора?
Каждая пауза на сборку мусора может вызвать нежелательные задержки - будь то паузы, которые заметит пользователь, или более длительная обработка HTTP-запроса. К сожалению, на момент .NET 5 нет поддержки в их измерении. Нет специального счетчика производительности или счетчика событий. И подходящего API сборщика мусора также нет. Но это не значит, что мы не можем это измерить! Лучший способ - собрать трассировку с помощью инструмента PerfView или
22. В чём особенность типа ref struct?
Ref struct - это особый тип структуры, представленный в C# 7.2. Он накладывает множество ограничений на поведение структуры с целью избежать попадания экземпляра ref struct в управляемую кучу. Обычная структура может попасть туда, например, при явной или неявной упаковке или если она является полем класса.
Все эти условия запрещены для
Но наиболее важным результатом этих ограничений является то, что она может содержать управляемый указатель. Или типы, содержащие управляемый указатель (например,
23. Циклические ссылки замедляют на сборку мусора и влияют на производительность?
Циклические ссылки обычно проблематичны для алгоритмов сборки мусора, использующих подсчёт ссылок. В наивных реализациях объекты, образующие циклическую ссылку, не могут быть собраны, потому что всегда есть по крайней мере один объект, указывающий на другой. Есть более сложные алгоритмы подсчёта ссылок с некоторыми дополнительными накладными расходами для обработки циклических ссылок.
Но .NET GC не использует подсчёт ссылок. Он использует так называемую трассировочную сборку мусора, которая основана на «отслеживании» того, что действительно всё ещё доступно из кода. Такая трассировка является умной - она посещает каждый объект только один раз, даже если между объектами существуют сложные зависимости. Другими словами, циклические ссылки вообще не влияют на производительность сборки мусора в .NET.
24. Чем ValueTask «лучше» Task в смысле потребляемой памяти?
Продолжение следует…
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Продолжение 21-24
Начало 1-4
Продолжение 5-8
Продолжение 9-12
Продолжение 13-16
Продолжение 17-20
21. Как измерить время паузы на сборку мусора?
Каждая пауза на сборку мусора может вызвать нежелательные задержки - будь то паузы, которые заметит пользователь, или более длительная обработка HTTP-запроса. К сожалению, на момент .NET 5 нет поддержки в их измерении. Нет специального счетчика производительности или счетчика событий. И подходящего API сборщика мусора также нет. Но это не значит, что мы не можем это измерить! Лучший способ - собрать трассировку с помощью инструмента PerfView или
dotnet trace и просмотреть отчет GC Stats в PerfView.22. В чём особенность типа ref struct?
Ref struct - это особый тип структуры, представленный в C# 7.2. Он накладывает множество ограничений на поведение структуры с целью избежать попадания экземпляра ref struct в управляемую кучу. Обычная структура может попасть туда, например, при явной или неявной упаковке или если она является полем класса.
Все эти условия запрещены для
ref struct. Благодаря этому гарантировано, что она всегда будет находиться в стеке (или регистрах процессора). Это ограничение может быть интересным само по себе: структура данных в стеке не требует многопоточной синхронизации, поскольку по умолчанию к ней нельзя получить доступ из нескольких потоков. И у нас есть гарантия, что она никогда не повлияет на сборщик мусора.Но наиболее важным результатом этих ограничений является то, что она может содержать управляемый указатель. Или типы, содержащие управляемый указатель (например,
Span<T>). Таким образом, это довольно популярный тип, используемый в низкоуровневом программировании.23. Циклические ссылки замедляют на сборку мусора и влияют на производительность?
Циклические ссылки обычно проблематичны для алгоритмов сборки мусора, использующих подсчёт ссылок. В наивных реализациях объекты, образующие циклическую ссылку, не могут быть собраны, потому что всегда есть по крайней мере один объект, указывающий на другой. Есть более сложные алгоритмы подсчёта ссылок с некоторыми дополнительными накладными расходами для обработки циклических ссылок.
Но .NET GC не использует подсчёт ссылок. Он использует так называемую трассировочную сборку мусора, которая основана на «отслеживании» того, что действительно всё ещё доступно из кода. Такая трассировка является умной - она посещает каждый объект только один раз, даже если между объектами существуют сложные зависимости. Другими словами, циклические ссылки вообще не влияют на производительность сборки мусора в .NET.
24. Чем ValueTask «лучше» Task в смысле потребляемой памяти?
ValueTask - это структура. Таким образом, используя его, мы получаем выгоду от того, что экземпляр не будет размещен в управляемой куче. Это может произойти в «счастливом» синхронном пути асинхронной операции - мы уже знаем результат, поэтому мы можем передать его через структуру, вместо того чтобы выделять Task только для передачи результата. Однако мы не можем гарантировать, что ValueTask никогда не будет упакован, потому что в «несчастливом» асинхронном случае он может быть упакован внутри конечного автомата, отслеживающего операцию.Продолжение следует…
Источник: https://dotnetmemoryexpert.com
День восемьсот сорок пятый. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Продолжение 25-27
Начало 1-4
Продолжение 5-8
Продолжение 9-12
Продолжение 13-16
Продолжение 17-20
Продолжение 21-24
25. Что такое интернирование строк?
Интернирование строк - это метод, позволяющий не дублировать экземпляры строк с одинаковым значением, известным во время компиляции. Таким образом, каждый раз, когда вы используете строковый литерал вроде
Дедупликация динамически создаваемых строк (со значением, неизвестным во время компиляции) не использует пул, потому что накладные расходы на проверку того, существует ли уже строка с заданным значением, вероятно, сократят преимущество от невыделения новой строки. В настоящее время открыт вопрос о дедупликации строк в фоновом режиме, но она пока не реализована.
Существует потокобезопасный API, с помощью которого вы можете получить доступ к пулу строк, чтобы проверить, интернирована ли строка с заданным значением (
26. Какие аллокации происходят в следующем методе:
Каждая лямбда также выделяет экземпляр
Примечание: статические лямбда-функции – нововведение в C#9.
27. Приводит ли ToString() на структуре к боксингу?
Окончание следует…
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .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
День восемьсот сорок седьмой. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Окончание 28-32
Предыдущие вопросы: 1-4, 5-8, 9-12, 13-16, 17-20, 21-24, 25-27
28. Что такое хвост распределения задержек (tail latency)?
Хвост распределения задержек - это небольшой процент ответов системы с наибольшим временем отклика. Обычно, рассматривая производительность, например, веб-приложения, нас интересует «среднее время отклика». Оно сообщает нам, каково время отклика для среднестатистического пользователя. Это может быть важным, но также и вводящим в заблуждение. Особенно, если распределение времени отклика является мультимодальным, т.е. когда существуют различные группы времён отклика (например, большинство - очень быстрые, но есть и другая группа очень медленных). Поэтому лучше измерять производительность, наблюдая гистограмму времени отклика, а также следить за хвостом распределения задержек.
Оптимизация хвоста распределения задержек важна, потому что даже если наше приложение работает достаточно хорошо, всё равно будут те несколько процентов пользователей, которые наблюдают действительно медленные ответы. Они могут разочароваться в нашем приложении и больше к нему не возвращаться.
В контексте GC хвост распределения задержек может возникать из-за случайных, но очень длинных пауз на сборку мусора.
29. В чём особенность метода Dispose?
Метод
30. Можно ли добиться детерминированных пауз на сборку мусора?
Короткий ответ - нет. Мы можем повлиять на время паузы: всё, что снижает нагрузку на память (например, уменьшение количества аллокаций), скорее всего уменьшит время пауз. Некоторые настройки GC тоже могут влиять на них. Но нет гарантии, что время паузы будет детерминированным (например, всегда меньше X миллисекунд). На рынке есть другие сборщики мусора, особенно в мире JVM, которые предоставляют такие гарантии. В .NET их пока нет.
31. Где можно настроить режим GC: серверный или рабочей станции?
Мы можем изменить режим GC только перед запуском приложения, но не во время его выполнения. Для этой цели можно использовать как файл конфигурации, так и переменные среды. Выбор между конкурентным (фоновым) и неконкурентным режимами сборки мусора не зависит от того, работает ли текущий сборщик мусора в режиме рабочей станцией или сервера.
32. Можем ли мы заменить сборщик мусора в .NET?
Да, можем! Начиная с .NET Core 2.0, GC и среда выполнения были разделены. С помощью переменной среды
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Окончание 28-32
Предыдущие вопросы: 1-4, 5-8, 9-12, 13-16, 17-20, 21-24, 25-27
28. Что такое хвост распределения задержек (tail latency)?
Хвост распределения задержек - это небольшой процент ответов системы с наибольшим временем отклика. Обычно, рассматривая производительность, например, веб-приложения, нас интересует «среднее время отклика». Оно сообщает нам, каково время отклика для среднестатистического пользователя. Это может быть важным, но также и вводящим в заблуждение. Особенно, если распределение времени отклика является мультимодальным, т.е. когда существуют различные группы времён отклика (например, большинство - очень быстрые, но есть и другая группа очень медленных). Поэтому лучше измерять производительность, наблюдая гистограмму времени отклика, а также следить за хвостом распределения задержек.
Оптимизация хвоста распределения задержек важна, потому что даже если наше приложение работает достаточно хорошо, всё равно будут те несколько процентов пользователей, которые наблюдают действительно медленные ответы. Они могут разочароваться в нашем приложении и больше к нему не возвращаться.
В контексте GC хвост распределения задержек может возникать из-за случайных, но очень длинных пауз на сборку мусора.
29. В чём особенность метода Dispose?
Метод
Dispose - это контракт, представленный интерфейсом IDisposable. Реализуя его, мы явно говорим: «экземпляры этого типа владеют некоторыми ресурсами, которые требуют явной очистки путём вызова метода Dispose». Вот и всё! Что делает метод Dispose, полностью зависит от конкретного случая. Важно помнить, что он не имеет ничего общего с GC и управляемой памятью. Это просто метод, который нужно вызвать. Мы можем вызвать его неявно через using и проверить, вызывается ли он, с помощью анализаторов кода. Вызов его ни о чём не сообщает сборщику мусора и не «освобождает память» после объекта. Такой объект, как и любой другой объект .NET, будет обработан сборщиком мусора, когда сборщик мусора обнаружит, что он больше не используется.30. Можно ли добиться детерминированных пауз на сборку мусора?
Короткий ответ - нет. Мы можем повлиять на время паузы: всё, что снижает нагрузку на память (например, уменьшение количества аллокаций), скорее всего уменьшит время пауз. Некоторые настройки GC тоже могут влиять на них. Но нет гарантии, что время паузы будет детерминированным (например, всегда меньше X миллисекунд). На рынке есть другие сборщики мусора, особенно в мире JVM, которые предоставляют такие гарантии. В .NET их пока нет.
31. Где можно настроить режим GC: серверный или рабочей станции?
Мы можем изменить режим GC только перед запуском приложения, но не во время его выполнения. Для этой цели можно использовать как файл конфигурации, так и переменные среды. Выбор между конкурентным (фоновым) и неконкурентным режимами сборки мусора не зависит от того, работает ли текущий сборщик мусора в режиме рабочей станцией или сервера.
32. Можем ли мы заменить сборщик мусора в .NET?
Да, можем! Начиная с .NET Core 2.0, GC и среда выполнения были разделены. С помощью переменной среды
COMPlus_GCName вы можете указать динамическую библиотеку, которая реализует ваш собственный сборщик мусора, и она будет использоваться средой выполнения .NET Core или .NET 5 вместо библиотеки по умолчанию. Однако есть одна проблема: на рынке нет готовых пользовательских сборщиков мусора.Источник: https://dotnetmemoryexpert.com
День восемьсот шестьдесят четвёртый.
Почему ASP.NET Приложение Такое Медленное? 10 Проблем с Производительностью и Их Решения. Продолжение
Начало (1)
2. Давление на память (Memory pressure)
Одной из наиболее распространённых проблем на серверах с высокой нагрузкой является давление на память. В этом состоянии сборщик мусора не успевает частыми созданиями и уничтожениями объектов в памяти. Когда сборщик мусора находится под давлением, ваш сервер тратит больше времени на сборку мусора и меньше времени на выполнение кода.
Это может произойти в нескольких случаях. Самый распространенный случай - когда заканчивается память. Когда вы достигнете предела памяти, сборщик мусора «паникует» и начинает инициировать более частые полные сборки мусора (они самые дорогие). Но вопрос в том, почему это вообще происходит? Почему возникает нехватка памяти? Причиной этого обычно является плохое управление кэшем или утечки памяти. Это довольно легко выяснить с помощью профилировщика, сделав снимок памяти и проверив, что занимает место.
Как и в случае с БД, самое важное - понять, что проблемы именно с памятью. Самый простой способ узнать это - использовать счетчики производительности.
Подробнее о работе с памятью.
3. Неоптимальный режим GC
Сборщик мусора .NET имеет два разных режима: режим GC рабочей станции и режим GC сервера. Первый оптимизирован для быстрого ответа с минимальным использованием ресурсов, а второй - для высокой пропускной способности.
Среда выполнения .NET по умолчанию устанавливает режим рабочей станции в настольных приложениях и режим сервера на серверах. Это значение по умолчанию почти всегда подходит. В случае сервера сборщик мусора будет использовать гораздо больше машинных ресурсов, но сможет обрабатывать больше запросов. Другими словами, у процесса будет больше потоков, выделенных для сборки мусора, и он сможет освобождать больше байт памяти в секунду.
По какой-либо причине ваш сервер может работать в режиме рабочей станции, и переход в режим сервера повысит производительность. В редких случаях вам может потребоваться установить режим сборки мусора сервера на рабочую станцию, что может быть разумным, если вы хотите, чтобы сервер потреблял меньше машинных ресурсов.
Подробнее про сборщик мусора см. посты по тегу #GC.
4. Отсутствие кэширования
Кэширование может быть отличным методом оптимизации. Канонический пример: когда клиент отправляет запрос, сервер может сохранить результат в кэше. Когда клиент снова отправляет тот же запрос (это может быть другой клиент или тот же самый), серверу не нужно снова запрашивать базу данных или производить какие-либо вычисления для получения результата. Он просто извлекает его из кэша.
Простой пример этого - поиск чего-либо в Google. Если это что-то распространённое, то, вероятно, это запрашивают много раз в день. Нет смысла повторять всю магию Google, чтобы получить первую страницу с теми же 10 результатами. Её можно получить из кэша.
Компромисс в том, что кэш добавляет сложности. Во-первых, вам нужно время от времени аннулировать этот кэш. В случае поиска Google учтите, что при поиске новостей нельзя всегда возвращать один и тот же результат. Другая проблема с кэшем заключается в том, что при неправильном управлении он может раздуться и вызвать проблемы с памятью.
В ASP.NET, есть отличные реализации кеширования, которые делают большую часть работы за вас.
Продолжение следует…
Источник: https://michaelscodingspot.com/slow-asp-net-server/
Почему ASP.NET Приложение Такое Медленное? 10 Проблем с Производительностью и Их Решения. Продолжение
Начало (1)
2. Давление на память (Memory pressure)
Одной из наиболее распространённых проблем на серверах с высокой нагрузкой является давление на память. В этом состоянии сборщик мусора не успевает частыми созданиями и уничтожениями объектов в памяти. Когда сборщик мусора находится под давлением, ваш сервер тратит больше времени на сборку мусора и меньше времени на выполнение кода.
Это может произойти в нескольких случаях. Самый распространенный случай - когда заканчивается память. Когда вы достигнете предела памяти, сборщик мусора «паникует» и начинает инициировать более частые полные сборки мусора (они самые дорогие). Но вопрос в том, почему это вообще происходит? Почему возникает нехватка памяти? Причиной этого обычно является плохое управление кэшем или утечки памяти. Это довольно легко выяснить с помощью профилировщика, сделав снимок памяти и проверив, что занимает место.
Как и в случае с БД, самое важное - понять, что проблемы именно с памятью. Самый простой способ узнать это - использовать счетчики производительности.
Подробнее о работе с памятью.
3. Неоптимальный режим GC
Сборщик мусора .NET имеет два разных режима: режим GC рабочей станции и режим GC сервера. Первый оптимизирован для быстрого ответа с минимальным использованием ресурсов, а второй - для высокой пропускной способности.
Среда выполнения .NET по умолчанию устанавливает режим рабочей станции в настольных приложениях и режим сервера на серверах. Это значение по умолчанию почти всегда подходит. В случае сервера сборщик мусора будет использовать гораздо больше машинных ресурсов, но сможет обрабатывать больше запросов. Другими словами, у процесса будет больше потоков, выделенных для сборки мусора, и он сможет освобождать больше байт памяти в секунду.
По какой-либо причине ваш сервер может работать в режиме рабочей станции, и переход в режим сервера повысит производительность. В редких случаях вам может потребоваться установить режим сборки мусора сервера на рабочую станцию, что может быть разумным, если вы хотите, чтобы сервер потреблял меньше машинных ресурсов.
Подробнее про сборщик мусора см. посты по тегу #GC.
4. Отсутствие кэширования
Кэширование может быть отличным методом оптимизации. Канонический пример: когда клиент отправляет запрос, сервер может сохранить результат в кэше. Когда клиент снова отправляет тот же запрос (это может быть другой клиент или тот же самый), серверу не нужно снова запрашивать базу данных или производить какие-либо вычисления для получения результата. Он просто извлекает его из кэша.
Простой пример этого - поиск чего-либо в Google. Если это что-то распространённое, то, вероятно, это запрашивают много раз в день. Нет смысла повторять всю магию Google, чтобы получить первую страницу с теми же 10 результатами. Её можно получить из кэша.
Компромисс в том, что кэш добавляет сложности. Во-первых, вам нужно время от времени аннулировать этот кэш. В случае поиска Google учтите, что при поиске новостей нельзя всегда возвращать один и тот же результат. Другая проблема с кэшем заключается в том, что при неправильном управлении он может раздуться и вызвать проблемы с памятью.
В ASP.NET, есть отличные реализации кеширования, которые делают большую часть работы за вас.
Продолжение следует…
Источник: https://michaelscodingspot.com/slow-asp-net-server/
День 1191.
Подборка тегов, используемых в постах на канале, чтобы облегчить поиск. Не могу гарантировать, что все 1190 постов идеально и корректно помечены тегами, но всё-таки, эта подборка должна помочь.
Общие
Эти посты на совершенно разные темы, помечены этими тегами только с целью различать общую направленность поста.
#ЗаметкиНаПолях – технические посты. Краткие описания теории, особенности языка C# и платформы .NET, примеры кода, и т.п.
#Шпаргалка - примеры кода, команды для утилит и т.п.
#Юмор – шутки, комиксы и просто весёлые тексты или ссылки на видео.
#Оффтоп – всё прочее.
Специализированные
Эти теги более тематические, выделяют основную тему поста.
#Карьера – советы по повышению продуктивности, карьерному росту, прохождению собеседований и т.п.
#Книги – обзоры книг, которые (чаще всего) я лично прочитал, либо ещё нет, но советую прочитать.
#Курсы – обзоры и ссылки на онлайн курсы.
#МоиИнструменты – различные программы, утилиты и расширения IDE, которые я использую в работе.
#ЧтоНовенького – новости из мира .NET.
Узкоспециализированные
Эти теги относятся к определённой узкой теме.
#AsyncTips – серия постов из книги Стивена Клири “Конкурентность в C#”
#AsyncAwaitFAQ – серия постов “Самые Частые Ошибки при Работе с async/await.”
#BestPractices – советы по лучшим практикам, паттернам разработки.
#DesignPatterns – всё о паттернах проектирования, SOLID, IDEALS и т.п.
#DotNetAZ – серия постов с описанием терминов из мира .NET.
#GC – серия постов “Топ Вопросов о Памяти в .NET.” от Конрада Кокосы.
#MoreEffectiveCSharp – серия постов из книги Билла Вагнера “More Effective C#”.
#Testing – всё о тестировании кода.
#TipsAndTricks – советы и трюки, в основном по функционалу Visual Studio.
#Quiz - опросы в виде викторины.
#97Вещей – серия постов из книги “97 Вещей, Которые Должен Знать Каждый Программист”.
#ВопросыНаСобеседовании – тег говорит сам за себя, самые часто задаваемые вопросы на собеседовании по C#, ASP.NET и .NET.
#ЗадачиНаСобеседовании – похоже на вопросы, но здесь больше приводятся практические задачи. Чаще всего это 2 поста: собственно задача и ответ с разбором.
#КакСтатьСеньором – серия постов «Как Стать Сеньором» с советами о продвижении по карьерной лестнице.
Помимо этого, можно просто воспользоваться поиском по постам и попробовать найти то, что вам нужно.
Подборка тегов, используемых в постах на канале, чтобы облегчить поиск. Не могу гарантировать, что все 1190 постов идеально и корректно помечены тегами, но всё-таки, эта подборка должна помочь.
Общие
Эти посты на совершенно разные темы, помечены этими тегами только с целью различать общую направленность поста.
#ЗаметкиНаПолях – технические посты. Краткие описания теории, особенности языка C# и платформы .NET, примеры кода, и т.п.
#Шпаргалка - примеры кода, команды для утилит и т.п.
#Юмор – шутки, комиксы и просто весёлые тексты или ссылки на видео.
#Оффтоп – всё прочее.
Специализированные
Эти теги более тематические, выделяют основную тему поста.
#Карьера – советы по повышению продуктивности, карьерному росту, прохождению собеседований и т.п.
#Книги – обзоры книг, которые (чаще всего) я лично прочитал, либо ещё нет, но советую прочитать.
#Курсы – обзоры и ссылки на онлайн курсы.
#МоиИнструменты – различные программы, утилиты и расширения IDE, которые я использую в работе.
#ЧтоНовенького – новости из мира .NET.
Узкоспециализированные
Эти теги относятся к определённой узкой теме.
#AsyncTips – серия постов из книги Стивена Клири “Конкурентность в C#”
#AsyncAwaitFAQ – серия постов “Самые Частые Ошибки при Работе с async/await.”
#BestPractices – советы по лучшим практикам, паттернам разработки.
#DesignPatterns – всё о паттернах проектирования, SOLID, IDEALS и т.п.
#DotNetAZ – серия постов с описанием терминов из мира .NET.
#GC – серия постов “Топ Вопросов о Памяти в .NET.” от Конрада Кокосы.
#MoreEffectiveCSharp – серия постов из книги Билла Вагнера “More Effective C#”.
#Testing – всё о тестировании кода.
#TipsAndTricks – советы и трюки, в основном по функционалу Visual Studio.
#Quiz - опросы в виде викторины.
#97Вещей – серия постов из книги “97 Вещей, Которые Должен Знать Каждый Программист”.
#ВопросыНаСобеседовании – тег говорит сам за себя, самые часто задаваемые вопросы на собеседовании по C#, ASP.NET и .NET.
#ЗадачиНаСобеседовании – похоже на вопросы, но здесь больше приводятся практические задачи. Чаще всего это 2 поста: собственно задача и ответ с разбором.
#КакСтатьСеньором – серия постов «Как Стать Сеньором» с советами о продвижении по карьерной лестнице.
Помимо этого, можно просто воспользоваться поиском по постам и попробовать найти то, что вам нужно.
1👍60👎1