Генерация .NET 0 размер кучи
Можно ли установить минимальный размер кучи поколения 0 в .NET?
У меня есть следующая схема. У меня есть функция, которая выделяет около 20-30 МБ объектов 1 КБ, что-то с ними и завершает, оставляя все выделенные объекты GC-ed. Теперь, в Performance Monitor, я вижу, что размер кучи поколения 0 составляет 5-6 МБ, чего недостаточно, чтобы принять все 20-30 МБ объектов, которые мне нужны. Когда я начинаю выделять, в какой-то момент gen0 GC запускается, и поскольку все объекты необходимы, он продвигает их в gen1. В следующий раз GC начнет работать, эти объекты будут продвигаться в gen2. Итак, наконец, около 15 МБ моих объектов попадают в кучу gen2. Это, по моей логике, временные объекты, которые никоим образом не должны заканчиваться в куче gen2. Я верю, что проблема заключается в размере размера кучи gen0. Но я не уверен. Я знаю, что в Java есть возможность установить минимальный размер кучи поколений. Есть ли такой способ в .NET?
Ответы
Ответ 1
Размер разных поколений - это деталь реализации, и я не знаю, как настроить ее для приложений .NET. Если моя память служит мне правильно, то поколение 0 и 1 разделяет один сегмент, который составляет 16 МБ в Win32, поэтому, если вы создадите множество объектов, некоторые из них будут продвигаться к более высоким поколениям, если они все еще ссылаются (так же, как вы описываете).
Я предполагаю, что идея ограничения размера генерации 0 заключается в том, чтобы собрать коллекцию g0 дешево. Если поколение 0 может вырасти до любого размера, ваша общая производительность, скорее всего, пострадает.
EDIT: Я считаю, что у книги Джеффри Рихтера есть некоторые подробности об этом, поэтому вы можете проверить это.
EDIT2: состояния Richter (стр. 502-507), что начальный бюджет генератора 0 составляет 256 КБ, а начальный бюджет 1-го поколения - 2 МБ. Однако это не размер поколения. Бюджеты корректируются по мере необходимости и будут расти и сокращаться в зависимости от использования памяти приложения.
Joe Duffy Professional.NET Framework 2.0, однако, утверждает, что эрманские поколения (т.е. 0 и 1) разделяют один сегмент, который обычно составляет 16 МБ (стр. 117). Только поколение 2 позволяет расти по мере необходимости (я полагаю, что LOH также может расти по мере необходимости, но это не понятно мне из текста).
Ответ 2
Вы уверены, что больше не ссылаетесь на эти объекты? GC очень хорошо настраивается на нужды вашего приложения и не будет продвигать объекты в Generation 2, если у вас нет корней для этих объектов.
Я думаю, если вы выясните, где находятся эти корни, и убедитесь, что вы действительно больше не ссылаетесь на эти объекты где-нибудь, тогда GC начнет освобождать память для этих объектов и никогда не будет продвигать их в Generation 1, не говоря уже о поколении 2. Также, если вы это сделаете, тогда GC обнаружит, что вам нужно, чтобы генератор 0 был больше и увеличил размер кучи от вашего имени.
Ответ 3
Куча Generation 0 изначально рассчитана на ваш кэш процессора. Это значит, что небольшие временные объекты даже не нужно перемещать в основную память.
Ответ 4
Спасибо, ребята, за вашу помощь.
Уилль, очень интересная постановка. Я никогда не упоминал, что я храню эти 30 МБ объектов в массиве размером порядка 100000. Я сначала выделяю этот массив, а затем заполняю его объектами. Поскольку этот массив больше 85K, этот массив хранится в кучке больших объектов. Оказывается, для сбора мусора для сбора объектов в этой куче ему нужно запустить коллекцию gen2, поэтому каждый раз, когда в куче больших объектов недостаточно места, он запускает коллекцию gen2, что приводит к сбою производительности. Вот простой пример, который будет постоянно вызывать коллекцию gen2. Вам нужно запустить его в режиме отладки (из-за оптимизации компилятора).
static void Main(string[] args)
{
while (true)
{
byte[] objects = new byte[100000];
}
}
Означает ли это, что всякий раз, когда мне нужен временный массив размером более 85 КБ, этот массив попадет в огромную кучу объектов?
Ответ 5
Первое поколение может увеличиваться и уменьшаться, но в будущем. при запуске процесса инициализированная управляемая куча имеет фиксированный размер в генерации 0 256 КБ (что означает Рихтер), поскольку современные компьютеры имеют 256 и более памяти для 2-го уровня ЦП наличных денег.
Во-вторых. Андрей, ты прав. Когда какой-то объект настолько велик, он сразу переходит в gen2.
Я могу предположить, что вы хотели бы уменьшить размер gen0, чтобы чаще спросить GC, чтобы очистить неиспользуемое пространство и сохранить ваше приложение светлее. У меня такая же проблема на веб-сайте SilverLight и поиск решения. Я думаю, что, если код создает много объектов, у которых есть корни, а когда gen0 - это полные CLR-вызовы GC, которые перемещают их в gen1, а затем, когда объекты растут, больше перемещают их в gen2. Пусть говорят, что все 3 поколения почти полны. Тогда, например, GC. Что он будет делать. Просто ясное поколение? Как с 1-го и 2-го.
Я думаю, что решение проблемы с освещением памяти заключается в следующем. Сначала создайте небольшие и много объектов вместо больших по размеру и меньше в графе. Вторичные внутренние ссылки должны быть однонаправленными, а не хаотичными, ссылающимися друг на друга. Статические объекты, которые не создаются динамически, например, в соответствии с записями записей из базы данных, должны храниться в глобальных переменных и не создавать снова, когда код вызывает их.
Ответ 6
+1 Эндрю. GC является самонастраивающимся, он узнает о моделях памяти приложения на лету.
В вашем случае, если GC выполняет коллекцию Gen 0 и обнаруживает, что много объектов сохранилось/не было исправлено много памяти, сборщик мусора автоматически увеличит бюджет/квоту Gen 0.
Глядя на члены типа GC, похоже, что нет возможности программно настроить бюджеты/размер GC Generation.
Ответ 7
Я не думаю, что есть возможность установить эти значения в .NET GC.
На первый взгляд похоже, что эта конкретная ситуация оправдывает необходимость наличия таких расширенных параметров, но если это будет статический параметр, который повлияет на все время жизни вашей программы. Динамическая опция, которую вы могли бы установить во время выполнения, была бы идеальной.
Кроме того, я не думаю, что это сильно повлияет на производительность вашей программы, хотя, если вы можете увеличить размер gen (0), вы можете освободить некоторую память (и получить некоторую производительность).
Поскольку GC самонастраивается, gen (0) автоматически увеличит размер, и объекты BIG в конечном итоге будут собирать мусор, рано или поздно.