Аннотация:
Уже много сказано слов о том, что такое GC, чем он хорош и как лучше его применять. Но, наверно, очень многим хочется знать, как устроен конкретный GC. Данная статья открывает некоторые подробности устройcтва GC в .NET Framework.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Чистяков Влад (VladD2 ), Вы писали:
ЧВV>Аннотация: ЧВV>Уже много сказано слов о том, что такое GC, чем он хорош и как лучше его применять. Но, наверно, очень многим хочется знать, как устроен конкретный GC. Данная статья открывает некоторые подробности устройcтва GC в .NET Framework.
Это статья по мотивам
Вторым выступлением на платформе 2006 был круглый стол, посвященный вопросам производительности, проведенный Владом Чистяковым (VladD2) с участием российских (в том числе и с нашего сайта) и украинских MVP…
Здравствуйте, _FRED_, Вы писали:
_FR>Это статья по мотивам _FR>
_FR>Вторым выступлением на платформе 2006 был круглый стол, посвященный вопросам производительности, проведенный Владом Чистяковым (VladD2) с участием российских (в том числе и с нашего сайта) и украинских MVP…
Здравствуйте, Чистяков Влад (VladD2 ), Вы писали:
ЧВV>Аннотация: ЧВV>Уже много сказано слов о том, что такое GC, чем он хорош и как лучше его применять. Но, наверно, очень многим хочется знать, как устроен конкретный GC. Данная статья открывает некоторые подробности устройcтва GC в .NET Framework.
А вопросов подкинутть можно ? В том числе и флеймовых ?
1) ConcurrentGC работает начиная только с 1.1SP1 или же, как Рихтер писал — с самого начала ?
1.1) Возможна ли ситуация, когда работающий в параллельном потоке GC не успеет чистить память ?
2) Когда начинается сборка мусора ? Учитывая фразу про "эвристику" ?
3) Как\чем снаружи посмотреть workset ? Память я посмотрю в Task Manager, а workset ?
Надо именно для описываемого случая — посмотреть не стоит ли уменьшить в настройках размеры кэшей для предотвращения свопа.
4) Нельзя ли осветить работу LOH ? Несколько раз поднимал вопрос о "premature Out of Memory Exception", как его обозвали зарубежные коллеги (если быстро выделять и переставать использовать большие объекты типа Char[10Mb+-1Mb] — будет нехватка памяти непонятно почему. Особенно на 1.1 без SP1).
Непонятно — как такое вообще может быть, если GC чистит память КАЖДЫЙ раз, когда ее не хватает. Если там эвристика — тогда понятно, но хотелось бы про нее знать.
Я где-то туплю наверное или это так и надо — вторая половина статьи пока не написана или что?
Я про вот этот кусок: Использование нескольких процессоров
Concurent GC
Сборщик мусора, основанный на поколениях
Запуск процесса сборки мусора
Сегменты
Контекст размещения
Устройство объекта
Создание и инициализация объектов
Исключения в конструкторе и финализация
Вычисление графа достижимых объектов и корни GC
Алгоритм сканирования графа живых объектов
Корни GC
Барьер записи (write barrier)
Средства обнаружения утечек памяти и контроля за ее распределением
SoS
CLR Profiler
Нехватка памяти
Здравствуйте, Nikolay_P_I, Вы писали:
N_P>1) ConcurrentGC работает начиная только с 1.1SP1 или же, как Рихтер писал — с самого начала ?
Он работает по умолчанию во всех версиях дотнета. Просто регулировать его использование стало можно только после выхода сервиспаков и второй версии. Раньше управлять тем какой ЖЦ использовать можно было только если запускать рантайм дотнета программно (через COM).
N_P>1.1) Возможна ли ситуация, когда работающий в параллельном потоке GC не успеет чистить память ?
Очень теоритически. На практике это не является проблемой.
N_P>2) Когда начинается сборка мусора ? Учитывая фразу про "эвристику" ?
В статье же сказано:
1. При очередном выделении памяти GC замечает, что превышен размер нулевого поколения.
2. Приложение самостоятельно вызывает метод GC.Collect().
3. Нехватка памяти в ОС.
В нормальных условиях работает в основном только пункт 1.
N_P>3) Как\чем снаружи посмотреть workset ? Память я посмотрю в Task Manager, а workset ?
Task Manager-ом и посмотреть. Если не путаю, колонка "Mem usage" и есть WorkSet.
N_P>Надо именно для описываемого случая — посмотреть не стоит ли уменьшить в настройках размеры кэшей для предотвращения свопа.
Для этого нужно наблюдать за динамикой. В разделе посвященном нехватки памяти как раз об этом говорится. Лучшим инструментом тут является Process Exlorer от www.sysinternals.com.
N_P>4) Нельзя ли осветить работу LOH ?
Да в общем-то про LOH много не скажешь. Но попробовать можно.
N_P> Несколько раз поднимал вопрос о "premature Out of Memory Exception", как его обозвали зарубежные коллеги (если быстро выделять и переставать использовать большие объекты типа Char[10Mb+-1Mb] — будет нехватка памяти непонятно почему. Особенно на 1.1 без SP1).
Это извесная проблема. Вроде как вылечена во втором фрэймворке. Данная ситуация зачастую возникает в следствии фрагментации обычно кучи. Причем обычно это является следствием применения библиотек вроде сокетов. Они делают кучу pin-ов объектов, и при сборке мусора получается сильная фрагментация. Старные алгоритмы неумели разруливать эту ситуацию. Вроде как в 2.0 ввели повторное использование сегментов, что должно было устранить проблему или по крайней мере снизить ее влияние.
Однако и в 1.1 можно было бороться с проблемой выделяя буферы в LOH или насильственно продвигая их во второе поколение.
N_P>Непонятно — как такое вообще может быть, если GC чистит память КАЖДЫЙ раз, когда ее не хватает. Если там эвристика — тогда понятно, но хотелось бы про нее знать.
Память занимается сегментами. Ранее если сегмент второго поколения имел дыры внутри, то они никогда не заполнялись и не уплотнялись. Это могло приводить к ситуации когда при наличии моря памяти в системе ЖЦ нарывался на ее отсуствие (кончалась виртуалка). Выше я об этом уже говорил.
Проявляется ли данная проблема под вторым фрэймворком?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
N_P>>1) ConcurrentGC работает начиная только с 1.1SP1 или же, как Рихтер писал — с самого начала ? VD>Он работает по умолчанию во всех версиях дотнета. Просто регулировать его использование стало можно только после выхода сервиспаков и второй версии. Раньше управлять тем какой ЖЦ использовать можно было только если запускать рантайм дотнета программно (через COM).
Понятно. Просто у Рихтера этот параметр в .exe.config рассматривается, когда еще и 1.1 не было.
N_P>>1.1) Возможна ли ситуация, когда работающий в параллельном потоке GC не успеет чистить память ? VD>Очень теоритически. На практике это не является проблемой.
Ну и хорошо.
N_P>>2) Когда начинается сборка мусора ? Учитывая фразу про "эвристику" ? VD>В статье же сказано: VD>
1. При очередном выделении памяти GC замечает, что превышен размер нулевого поколения.
VD>2. Приложение самостоятельно вызывает метод GC.Collect().
VD>3. Нехватка памяти в ОС.
VD>В нормальных условиях работает в основном только пункт 1.
Угу. С Gen0\1 ясно. Про "эвристику" было относительно сборки в Gen2.
N_P>>3) Как\чем снаружи посмотреть workset ? Память я посмотрю в Task Manager, а workset ? VD>Task Manager-ом и посмотреть. Если не путаю, колонка "Mem usage" и есть WorkSet.
Ээээ ? А что тогда "память" ?
N_P>>Надо именно для описываемого случая — посмотреть не стоит ли уменьшить в настройках размеры кэшей для предотвращения свопа. VD>Для этого нужно наблюдать за динамикой. В разделе посвященном нехватки памяти как раз об этом говорится. Лучшим инструментом тут является Process Exlorer от www.sysinternals.com.
Методика понятна — хочется синхронизации в терминах — какие именно колонки где смотреть ?
N_P>>4) Нельзя ли осветить работу LOH ? VD>Да в общем-то про LOH много не скажешь. Но попробовать можно.
N_P>> Несколько раз поднимал вопрос о "premature Out of Memory Exception", как его обозвали зарубежные коллеги (если быстро выделять и переставать использовать большие объекты типа Char[10Mb+-1Mb] — будет нехватка памяти непонятно почему. Особенно на 1.1 без SP1).
VD>Это извесная проблема. Вроде как вылечена во втором фрэймворке. Данная ситуация зачастую возникает в следствии фрагментации обычно кучи. Причем обычно это является следствием применения библиотек вроде сокетов. Они делают кучу pin-ов объектов, и при сборке мусора получается сильная фрагментация. Старные алгоритмы неумели разруливать эту ситуацию. Вроде как в 2.0 ввели повторное использование сегментов, что должно было устранить проблему или по крайней мере снизить ее влияние.
Простейший пример с цикличным new Char[] все возрастающего объема — не должен иметь pin ? А оно там отлавливается стабильно.
VD>Однако и в 1.1 можно было бороться с проблемой выделяя буферы в LOH или насильственно продвигая их во второе поколение.
А как это ?
N_P>>Непонятно — как такое вообще может быть, если GC чистит память КАЖДЫЙ раз, когда ее не хватает. Если там эвристика — тогда понятно, но хотелось бы про нее знать. VD>Память занимается сегментами. Ранее если сегмент второго поколения имел дыры внутри, то они никогда не заполнялись и не уплотнялись. Это могло приводить к ситуации когда при наличии моря памяти в системе ЖЦ нарывался на ее отсуствие (кончалась виртуалка). Выше я об этом уже говорил.
Хмм... Не похоже. Я не утверждаю, но впечатление такое, что дело более тонкое — я не мог выделить Char[8307000]-Char[8390000], но Char[16000000] проходил. Кроме того — видимо, была зависимость от скорости — при долговременной работе с большими Char[] (обработка потока файлов) — все было нормально.
Свопа, кстати, не было во всех случаях и MemUsage сбрасывался к 80Мб потом стабильно.
VD>Проявляется ли данная проблема под вторым фрэймворком?
Хмм. Не совсем. С 1.1 пришлось уйти категорически — невозможность выделить 16Мб памяти — это нонсенс в наше время.
В 1.1 SP1 это дело неплохо поправили и граница в районе 100-200Мб. В 2.0 Еще лучше — там около 500Мб — возможно, это уже предел.
Здравствуйте, Nikolay_P_I, Вы писали:
N_P>Понятно. Просто у Рихтера этот параметр в .exe.config рассматривается, когда еще и 1.1 не было.
Он введен в сервиспаке. Если Рихтер писал книгу/статью полсе его выхода, то может быть.
N_P>>>2) Когда начинается сборка мусора ? Учитывая фразу про "эвристику" ? VD>>В статье же сказано: VD>>
1. При очередном выделении памяти GC замечает, что превышен размер нулевого поколения.
VD>>2. Приложение самостоятельно вызывает метод GC.Collect().
VD>>3. Нехватка памяти в ОС.
VD>>В нормальных условиях работает в основном только пункт 1.
N_P>Угу. С Gen0\1 ясно. Про "эвристику" было относительно сборки в Gen2.
Дык п. 1 на все поколения распростроняется. Инициируется сборка нехваткой места в поколении 0, но сораться может и второе поколение. Все зависит от того будет ли превышен порог для поколения или нет.
VD>>Task Manager-ом и посмотреть. Если не путаю, колонка "Mem usage" и есть WorkSet.
N_P>Ээээ ? А что тогда "память" ?
А память — это неопределенное понятие. Есть виртуальная память. Она так и называется.
Вообще в таск-менеджере есть хэлп в котором все описано:
Memory Usage
In Task Manager, the current working set of a process, in kilobytes. The current working set is the number of pages currently resident in memory. On the Task Manager Processes tab, the column heading is Mem Usage.
Virtual Memory Size
In Task Manager, the amount of virtual memory, or address space, committed to a process.
...
N_P>Методика понятна — хочется синхронизации в терминах — какие именно колонки где смотреть ?
Дык зависит от ситуации. В принципе динамика ворксета уже о многом говорит. Но иногда даже такая информация как количество page fault.
Лучше всего почитать описание процесс-эксплорера и такс-менеджера. Они о многом говорят. Так же если нет понимания, что такое виртуальная память и т.п. имеет смысл почитать Рихтера, но не про дотнет. А про Виндовс.
N_P>Простейший пример с цикличным new Char[] все возрастающего объема — не должен иметь pin ? А оно там отлавливается стабильно.
Где там? Конечно если занимать огромные массивы, то рано или поздно можно выйти на момент когда памяти не хватит. Но это слишком искуственная ситуация. Массивы большого объема нужно или вообще не занимать, или если уж занял, то деражать по дольше. Использовать повторно если можно...
VD>>Однако и в 1.1 можно было бороться с проблемой выделяя буферы в LOH или насильственно продвигая их во второе поколение.
N_P>А как это ?
Ну, чтобы буфер попал в LOH нужно просто выделить его размером более 85000 байт. А чтобы продвинуть во второе поколение — занять его (их) в начале работы программы и вызвать вручную пару сборок мусара.
N_P>Хмм... Не похоже. Я не утверждаю, но впечатление такое, что дело более тонкое — я не мог выделить Char[8307000]-Char[8390000], но Char[16000000] проходил. Кроме того — видимо, была зависимость от скорости — при долговременной работе с большими Char[] (обработка потока файлов) — все было нормально.
С файлами, кстати, такая байда тоже может быть. Любое обращение к неуправяемому API блокирует объект на время вызова. Если вызов по каким-то причинам длится долго, то может появиться описанная проблема. Так что большие буферы нужно занимать заранее и использовать рачительно.
N_P>Свопа, кстати, не было во всех случаях и MemUsage сбрасывался к 80Мб потом стабильно.
Дык если есть дыры, то примерно так и будет. Хотя тут конечно фиг угадашь.
VD>>Проявляется ли данная проблема под вторым фрэймворком?
N_P>Хмм. Не совсем. С 1.1 пришлось уйти категорически — невозможность выделить 16Мб памяти — это нонсенс в наше время.
У нас на сервере занимаются гигабайты памяти. Вопрос в том как это делать.
N_P>В 1.1 SP1 это дело неплохо поправили и граница в районе 100-200Мб. В 2.0 Еще лучше — там около 500Мб — возможно, это уже предел.
Нет таких ограничений. У меня вот такой тест:
using System;
using System.Collections.Generic;
using System.Text;
class Program
{
static void Main()
{
byte[] array = new byte[1024 * 1024 * 1024]; // Занимаем Гиг!!!for (int i = 0; i < array.Length; i++)
array[i] = (byte)(i % byte.MaxValue);
int sum = 0;
foreach (byte value in array)
sum += value;
Console.WriteLine("Тест прошел успешно :) sum = " + sum);
}
}
Проходит нормально выводя:
Тест прошел успешно :) sum = -1073747936
Press any key to continue . . .
И это при том, чо в системе в принципе есть только 1 Гиг памяти и в момент запуска теста занято было около 900 метров (т.е. почти все).
Ворксет при этом составляет около 300 метров, а виртуалки занято под гиг. Оно и понятно.
Просто суммарный объем занятой памяти на процесс не может превышать 2 гиг (3 для спец. режима ОС). Но это ограничения не дотнета, а 32-битной ОС.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Дык зависит от ситуации. В принципе динамика ворксета уже о многом говорит. Но иногда даже такая информация как количество page fault. VD>Лучше всего почитать описание процесс-эксплорера и такс-менеджера. Они о многом говорят. Так же если нет понимания, что такое виртуальная память и т.п. имеет смысл почитать Рихтера, но не про дотнет. А про Виндовс.
То есть — я правильно понял, что индикатором о недостатке памяти служит ворксет, который периодически пытается раздуться до размера виртуалки, а потом уменьшается до десятка Мб ? Имеет при этом значение размера виртуальной памяти само по-себе ? 2Гб виртуалки при 1Гб ОЗУ — тут ясно, а если виртуалки 300 Мб ?
N_P>>Простейший пример с цикличным new Char[] все возрастающего объема — не должен иметь pin ? А оно там отлавливается стабильно.
VD>Где там? Конечно если занимать огромные массивы, то рано или поздно можно выйти на момент когда памяти не хватит.
Почему ? Каков механизм ? Если не держать их, а отдавать. Пусть не будет сдвигания объектов, но дефрагментация-то будет работать ?
VD>Но это слишком искуственная ситуация. Массивы большого объема нужно или вообще не занимать,
>85кб на сегодняшний день — это никак не "массив большого объема"
N_P>>Хмм... Не похоже. Я не утверждаю, но впечатление такое, что дело более тонкое — я не мог выделить Char[8307000]-Char[8390000], но Char[16000000] проходил. Кроме того — видимо, была зависимость от скорости — при долговременной работе с большими Char[] (обработка потока файлов) — все было нормально. VD>С файлами, кстати, такая байда тоже может быть. Любое обращение к неуправяемому API блокирует объект на время вызова. Если вызов по каким-то причинам длится долго, то может появиться описанная проблема. Так что большие буферы нужно занимать заранее и использовать рачительно.
Там из файла только в начале в буфер читается. Средний размер 100кб-1Мб. Но может быть 1к-100Мб. Куча работ со строками и под-буферами.
Например, сторонняя библиотека хотит Byte[] материала с 2000 по end-5000 адрес входной информации. Выделяем — вот и еще 1 большой массив наклюнулся.
N_P>>Хмм. Не совсем. С 1.1 пришлось уйти категорически — невозможность выделить 16Мб памяти — это нонсенс в наше время. VD>У нас на сервере занимаются гигабайты памяти. Вопрос в том как это делать.
А как можно занять гигабайтЫ ? Интересно с практической точки зрения.
N_P>>В 1.1 SP1 это дело неплохо поправили и граница в районе 100-200Мб. В 2.0 Еще лучше — там около 500Мб — возможно, это уже предел. VD>Нет таких ограничений. У меня вот такой тест:
Ха! Хитрый какой! Ты не 1 раз этот гигабайт выделяй, а в динамике:
VD>
VD>using System;
VD>using System.Collections.Generic;
VD>using System.Text;
class Program
{
static void Main()
{
Int32 bs = 0;
try
{
while(true)
{
bs = bs + 10; //для 1.1 без SP1 - лучше 10, для прочих - 100byte[] array = new byte[bs * 1024 * 1024]; // Занимаем!!!
};
}
catch
{
Console.WriteLine(bs);
}
}
}
У меня Out of Memory на 230. Вопрос — а ПОЧЕМУ ? Ладно, не происходит сдвига объектов, но дефрагментация куда делась ?
P.S. Виртуальная память — совсем маленькая по Task Manager
Здравствуйте, Alex57, Вы писали:
A>если запускать не в среде то нормально, но не шибко быстро.
А что же ты хотел? На свопие сидишь. Погляди сколько у тебя физической памяти свободно. Измени размер массива чтобы он влезал в свободную память и все начнет летать.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Nikolay_P_I, Вы писали:
N_P>То есть — я правильно понял, что индикатором о недостатке памяти служит ворксет, который периодически пытается раздуться до размера виртуалки, а потом уменьшается до десятка Мб ?
Это как бы вернейший признак проблем. Но бывает, что не все так очевидно.
N_P> Имеет при этом значение размера виртуальной памяти само по-себе ?
Конечно. Если размер виртуалки приближается к объему физически установленной памяти, то проблемы практически гарантированны.
N_P> 2Гб виртуалки при 1Гб ОЗУ — тут ясно, а если виртуалки 300 Мб ?
Не понял вопроса.
N_P>Почему ? Каков механизм ? Если не держать их, а отдавать. Пусть не будет сдвигания объектов, но дефрагментация-то будет работать ?
Ну, массив в 3 гига занять в принципе невозможно. И надо учитывать, что память расходуется не толкьо под хипы ЖЦ. Она еще идет на внтуренние структуры, на джит... Вожно с помощью SoS и отладчика поглядеть раскладку памяти. Информация не очень понятна, но если разобраться, то все будет очевидно.
N_P>Там из файла только в начале в буфер читается. Средний размер 100кб-1Мб.
Это фигня.
N_P> Но может быть 1к-100Мб. Куча работ со строками и под-буферами.
А вот тут лучше читать через потоки.
N_P>Например, сторонняя библиотека хотит Byte[] материала с 2000 по end-5000 адрес входной информации. Выделяем — вот и еще 1 большой массив наклюнулся.
Он часто нужно? Может занять его один раз в начале пработы приложения?
N_P>А как можно занять гигабайтЫ ? Интересно с практической точки зрения.
Да просто. У нас на сервере делается дифф огномного файла. Сумарный объем занимаемой памяти приложением вылезает за гиг. На сервере 3 гига физической памяти и энтерпрайзная Вынь2003 с ключиком для подержки 3 гиг на процесс.
N_P>Ха! Хитрый какой! Ты не 1 раз этот гигабайт выделяй, а в динамике:
VD>>
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Nikolay_P_I, Вы писали:
N_P>> Имеет при этом значение размера виртуальной памяти само по-себе ? VD>Конечно. Если размер виртуалки приближается к объему физически установленной памяти, то проблемы практически гарантированны. N_P>> 2Гб виртуалки при 1Гб ОЗУ — тут ясно, а если виртуалки 300 Мб ? VD>Не понял вопроса.
Совместно с вышеприведенным — то есть в случае, когда виртуалка подходит к размеру ОЗУ — тут и так понятно — памяти не хватает.
Вопрос — а если виртуалки еще меньше, чем ОЗУ, но есть и прочие программы — как узнать — конкретно нам уже не хватает памяти или нет ?
По динамике изменения workset ?
N_P>>Там из файла только в начале в буфер читается. Средний размер 100кб-1Мб. VD>Это фигня.
Ага. Но уже >85к и LOH.
N_P>> Но может быть 1к-100Мб. Куча работ со строками и под-буферами. VD>А вот тут лучше читать через потоки.
Обработка НЕпотоковая.
N_P>>Например, сторонняя библиотека хотит Byte[] материала с 2000 по end-5000 адрес входной информации. Выделяем — вот и еще 1 большой массив наклюнулся. VD>Он часто нужно? Может занять его один раз в начале пработы приложения?
Никто не знает. Встретился ключ — отдай порцию инфы на обработку.
N_P>>А как можно занять гигабайтЫ ? Интересно с практической точки зрения. VD>Да просто. У нас на сервере делается дифф огномного файла. Сумарный объем занимаемой памяти приложением вылезает за гиг. На сервере 3 гига физической памяти и энтерпрайзная Вынь2003 с ключиком для подержки 3 гиг на процесс.
Ааа... Слышал про это — я думал — программно извратились
N_P>>Ха! Хитрый какой! Ты не 1 раз этот гигабайт выделяй, а в динамике:
VD>>>
N_P>>У меня Out of Memory на 230. Вопрос — а ПОЧЕМУ ? Ладно, не происходит сдвига объектов, но дефрагментация куда делась ? VD>Ну, это вообще не ясно что за код. В релизе думаю локальную переменную просто выкинут. Так что унжно код писать как-то так:
Я не подумал — однако в Release локальную не выкинули — я же проверял перед посылкой.
VD>
Здравствуйте, Nikolay_P_I, Вы писали:
N_P>Вопрос — а если виртуалки еще меньше, чем ОЗУ, но есть и прочие программы — как узнать — конкретно нам уже не хватает памяти или нет ?
Я не понимаю что значит "если виртуалки еще меньше".
N_P>По динамике изменения workset ?
Ну очень большие скачки workset-а — это точно не хорошо. Хотя сами скачки могут вызваться просто активизацией некого охочего до памяти алгоритма.
N_P>Ага. Но уже >85к и LOH.
Дык это же довольно быстро происходит. Если буферв не удерживаются долго, то ЖЦ их и не заметит. При сборке второго поколения их не станет.
Вот если между этими временными буферами занимается по 90 кил долгоживущих объектов, то это может привести к фрагментации LOH-а. Такого лучше избегать.
N_P>>> Но может быть 1к-100Мб. Куча работ со строками и под-буферами. VD>>А вот тут лучше читать через потоки.
N_P>Обработка НЕпотоковая.
Конкретнее, если можно. Что мешает ей быть потоковой?
N_P>Никто не знает. Встретился ключ — отдай порцию инфы на обработку.
Ну, и часто встречается? Пойми потерянный мег памяти может обойтись в итоге дешевле чем перезаемы больших кусков.
N_P>Ааа... Слышал про это — я думал — программно извратились
Смысла нет. И так дифф жрет реально больше чем следовало бы если заниматься подбором оптимальных значений буферов.
Дело в том, что после какого-то размера увеличение буферов если и дает что-то, то прирост очень незначителен. Но выявлять эти зависимости обычно в лом.
VD>>Ну, это вообще не ясно что за код. В релизе думаю локальную переменную просто выкинут. Так что унжно код писать как-то так:
N_P>Я не подумал — однако в Release локальную не выкинули — я же проверял перед посылкой.
Я вот, например, изменил в твоем коде пару строк и получил моментальную отработку. Явно компилятор выкинул бессмысленный код.
N_P>Вопрос-то в чем ? То, что в 2.0 это поправлено — я знаю. Вопрос в том, что непонятно, как на 1.1 SP1 получается такой результат.
Точно без наличия исходников это не установишь. Так что просто переходите на 2.0 и забывайте про 1.х к чертям.
N_P>Возвращаясь к статье — не выходит описанной простоты. Явно ведь есть еще какой-то хитрый механизм.
Хм. Простоты вообще добиться сложно. Особенно в сложных вещах. Но это уже философия.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
N_P>>Вопрос — а если виртуалки еще меньше, чем ОЗУ, но есть и прочие программы — как узнать — конкретно нам уже не хватает памяти или нет ? VD>Я не понимаю что значит "если виртуалки еще меньше".
Виртуальной памяти под данную программу занято менее объема ОЗУ, виртуальной памяти вообще всеми программами занято менее объема ОЗУ, workset нашей программы менее виртуальной памяти под нашу программу в пару раз и скачет +-20%.
N_P>>Ага. Но уже >85к и LOH. VD>Дык это же довольно быстро происходит. Если буферв не удерживаются долго, то ЖЦ их и не заметит. При сборке второго поколения их не станет. VD>Вот если между этими временными буферами занимается по 90 кил долгоживущих объектов, то это может привести к фрагментации LOH-а. Такого лучше избегать.
"Долгоживущих" здесь имеется ввиду — тоже больших, которые в LOH? А ежели и они потом соберутся так как не нужны ?
В смысле — работа циклическая и после того, как очередной файл обработан — никакие созданные при обработке предыдущего файла объекты и буфера не нужны, кроме нескольких новых объектов в очереди лога, которые долгоживущие, но маленькие.
N_P>>>> Но может быть 1к-100Мб. Куча работ со строками и под-буферами. VD>>>А вот тут лучше читать через потоки. N_P>>Обработка НЕпотоковая. VD>Конкретнее, если можно. Что мешает ей быть потоковой?
Тип фрагмента (и что с ним делать соответственно) — я знаю только после его конца. (Читать "задом-на-перед" не предлагать).
Да и не поможет — я-ж пишу — библиотека стронняя хочет не поток, а массив на входе. И вернет, кстати, тоже массив, но иной длинны. Максимум что я могу — буфер выделить из прочитанного, а потом его в библиотеку отдать. Разницы, если я еще и файл сначала в еще один буфер загоню — почти никакой. Зато обработка легче — вместо автомата на поток — просто регексы.
N_P>>Никто не знает. Встретился ключ — отдай порцию инфы на обработку. VD>Ну, и часто встречается? Пойми потерянный мег памяти может обойтись в итоге дешевле чем перезаемы больших кусков.
Постоянно. Там доморощенный изврат на тему MIME. Так что может быть и 2000 кусков по 1Мб и 1 кусок на 200Мб.
VD>>>Ну, это вообще не ясно что за код. В релизе думаю локальную переменную просто выкинут. Так что унжно код писать как-то так: N_P>>Я не подумал — однако в Release локальную не выкинули — я же проверял перед посылкой. VD>Я вот, например, изменил в твоем коде пару строк и получил моментальную отработку. Явно компилятор выкинул бессмысленный код.
Я получал Out of Memory на 220 границы в 1.1 SP1 — не мог он выкинуть в моем случае создание массива.
N_P>>Вопрос-то в чем ? То, что в 2.0 это поправлено — я знаю. Вопрос в том, что непонятно, как на 1.1 SP1 получается такой результат. VD>Точно без наличия исходников это не установишь. Так что просто переходите на 2.0 и забывайте про 1.х к чертям. N_P>>Возвращаясь к статье — не выходит описанной простоты. Явно ведь есть еще какой-то хитрый механизм. VD>Хм. Простоты вообще добиться сложно. Особенно в сложных вещах. Но это уже философия.
Тебе-то смешно... Это теперь, с появлением 2.0 он филосовский. А представь — мы выбирали пару лет назад единую платформу под проект, заинтересовались NET, упирая в первую очередь на надежность, начитались умных книжек типа Рихтера и таких вот статей, где с CG все просто и хорошо — как памяти не хватает, так ее ОБЯЗАТЕЛЬНО очистят, соберут, подвинут или в крайнем случае дефрагментируют, решили смириться с частым GC в обмен на простоту и универсальность алгоритма,сделали работу, поставили на стенд и получили Out of Memory на 16Мб кусках в динамике. Был тогда у нас 1.1 без SP.
Начали выяснять ситуацию и оказалось, что умные книги и статьи, видимо, несколько УПРОЩАЮТ и все несколько не так. К счастью — по ТЗ в динамике нам выделать можно и не более 200Мб, так что 1.1 SP1 нас спас. Прикинь, что были-бы требования до 500Мб. 2.0 еще не было.
Здравствуйте, Чистяков Влад (VladD2 ), Вы писали:
ЧВV>Уже много сказано слов о том, что такое GC, чем он хорош и как лучше его применять.
Спасибо, статья оказалась вполне "для меня", несмотря на наличие подробностей и деталей. Всё-таки не так-то и просто оказалось после Object Pascal вписать в мировозрение этот Сборщик мусора. Хотя, конечно, ничего нового и не было изобретено, но это видно после прочтения статьи.
Здравствуйте, Чистяков Влад (VladD2 ), Вы писали:
ЧВV>Аннотация: ЧВV>Уже много сказано слов о том, что такое GC, чем он хорош и как лучше его применять. Но, наверно, очень многим хочется знать, как устроен конкретный GC. Данная статья открывает некоторые подробности устройcтва GC в .NET Framework.
Есть разные способы учета ссылок из прошлых поколений. К сожалению, я не смог найти точную информацию о том, какой способ используется в .NET. Но по сути это и не важно. Важно понимать, что копирование ссылки на объект в поле другого объекта в .NET стоит дороже, нежели в неуправляемых языках. Это, можно сказать, плата за автоматическое управление памятью. В сумме со временем, затрачиваемым на уборку мусора, время, затрачиваемое на барьер записи, составляет основные затраты времени на управление памятью.
В .NET используется механизм защиты виртуальной памяти, а точнее функция GetWriteWatch (подробности на нее можно посмотреть в MSDN). То есть помечаются не отдельные ссылки на старое поколение, а страницы памяти, которые могут содержать эти ссылки.
Еще видел в блоге девелопера (но сейчас не могу найти), что в новых версиях .NET будет использоваться card marking (в Sun JVM он используется уже давно ). При помощи card marking'а так же отслеживается не точное положение ссылки, а "карта" (небольшой блок памяти, обычно 256-512 байт) в которой она находится. По сравнению с виртуальными страницами памяти имеем меньший оверхед по сканированию.
Здравствуйте, Cyberax, Вы писали:
C>Еще видел в блоге девелопера (но сейчас не могу найти), что в новых версиях .NET будет использоваться card marking (в Sun JVM он используется уже давно ). При помощи card marking'а так же отслеживается не точное положение ссылки, а "карта" (небольшой блок памяти, обычно 256-512 байт) в которой она находится. По сравнению с виртуальными страницами памяти имеем меньший оверхед по сканированию.
Отслеживание страниц — это и есть разновидность тарточной пометки. Так что вопрос только в размере блока.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Однако не могу согласиться со следующим утверждением:
...Многие противники GC, не находя аргументов, заявляют, что «GC не пригодно для задач реального времени». Сборщик мусора, реализованный в .NET, действительно непригоден для задач реального времени. Однако будем честными друг с другом – многие ли занимаются такими задачами?
При разработке служб Windows часто приходится решать задачи реального времени.
Здравствуйте, VladD2, Вы писали:
C>>Еще видел в блоге девелопера (но сейчас не могу найти), что в новых версиях .NET будет использоваться card marking (в Sun JVM он используется уже давно ). При помощи card marking'а так же отслеживается не точное положение ссылки, а "карта" (небольшой блок памяти, обычно 256-512 байт) в которой она находится. По сравнению с виртуальными страницами памяти имеем меньший оверхед по сканированию. VD>Отслеживание страниц — это и есть разновидность тарточной пометки. Так что вопрос только в размере блока.
Под "card marking" понимают именно явную пометку в таблице карт.
RB>При разработке служб Windows часто приходится решать задачи реального времени.
Поясните пожалуйста это утверждение. Каких конкретно служб. И еще надо учесть, что Windows — не ОС реального времени, поэтому говорить о задачах реального времени
сложно.
RB>>При разработке служб Windows часто приходится решать задачи реального времени. NC>Поясните пожалуйста это утверждение. Каких конкретно служб. И еще надо учесть, что Windows — не ОС реального времени, поэтому говорить о задачах реального времени NC>сложно.
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, Red Bird, Вы писали:
RB>>Например, чтение входящих сообщений (e-mail). WH>Гм... а зачем тут реальное время?
И не говори... Нафига ограниченное время реакции на письмо, если само письмо может идти неограниченно долго
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Red Bird, Вы писали:
RB>При разработке служб Windows часто приходится решать задачи реального времени.
Если не пользоваться определениями с базара, то весь Виндовс не пригоден для решения задач реального времени, так как вообще не обеспечивает хоть какого-то гарантированного времени отклика.
То что ты называшь "решать задачи реального времени" на самом деле не являются задачами реального времени. Это просто задачи требующие быстрого отлика в болшинстве случаев.
GC в .NET более чем пригоден для таких задач. Так на нем без проблем можно писать игры или серверы для игр. Да и для большинства задач обработки данных он пригоден. Единственное что нужно делать — это кэшировать входной поток данных. А вот писать программы интерактивно возаимодействующие с аппаратурой на Виндовс нельзя. По крайней мере критические (приводящие к аппоратным сбоям в случае если программа не успеет среагировать).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Red Bird, Вы писали:
RB>Например, чтение входящих сообщений (e-mail).
Даже задача вроде "Instant messenger" не является задачами реального времени. Она требует быстрой реакции программы в общем случае и не критична если программа иногда (например раз в 10 часов) задумается на пол секунды (огромное время по машинным меркам).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, Чистяков Влад (VladD2 ), Вы писали:
ANS>Эта, Влад, RASDN же под .Net? А можно привести статистику работы GC с RSDN — размеры поколений, частота сборок, продолжительность пауз?
Можно, но смысла нет. Основное время отедает MS SQL (агреггирующие запросы). ЖЦ практически не влияет на работу. Сборка мусора нулевого поколения просходит раз 1-4 секунды. Раз в 10 секунд просходит сборка второго поколения. Где-то так же первого. Время проведенное в GC колеблится от 0.3% до 3%. В среднем меньше 1%.
MS SQL отжирает 1.6 гига из доступных 3-х. Дотнет 200-300 метров. Периодически поднимается долбаный Перл которым толи спамфильтр проверяется, то ли еще что. Так эта зараза отжирает памяти примерно столько же как основной процесс сайта.
Второе по значимости приложение на дотнете — NNTP-сервер с 17-го числа произвел 600 сборок мусора второго поколения. Время в GC менее 0.01%.
Короче, не влияет ЖЦ тут ни на что.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Можно, но смысла нет. Основное время отедает MS SQL (агреггирующие запросы). ЖЦ практически не влияет на работу. Сборка мусора нулевого поколения просходит раз 1-4 секунды. Раз в 10 секунд просходит сборка второго поколения. Где-то так же первого. Время проведенное в GC колеблится от 0.3% до 3%. В среднем меньше 1%.
А размеры поколений?
ЗЫ. У меня сложилось впечатление, что днём всё заметно медленнее работает. У тебя есть какая-то статистика?
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>ЗЫ. У меня сложилось впечатление, что днём всё заметно медленнее работает. У тебя есть какая-то статистика?
Так по тому что днем приходит много народа.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
ANS>>ЗЫ. У меня сложилось впечатление, что днём всё заметно медленнее работает. У тебя есть какая-то статистика? WH>Так по тому что днем приходит много народа.
Мне это действительно интересно. Хотелось бы увидеть что-то дневное и ночное в числовом выражении. Ну, там среднее время отдачи страницы с одним /случайным/ сообщением, распределение по поколениям, процент простоя от GC.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>А размеры поколений?
ANS>ЗЫ. У меня сложилось впечатление, что днём всё заметно медленнее работает. У тебя есть какая-то статистика?
Все упирается в SQL-сервер. Есть некое число запросов которые могут пройти в секунду. Кокда пользователей много (с 10 до 16 и особенно с 11 до 14), то они просто выстраиваются в очеред и получаются тормоза.
В этом в основном виноват и движок сайта который не исползует агрегирование информации. Объем данных все время растет и количество пользователей тоже (хотя оно сдерживается скоростью сайта). Вот на сегодня движок и тормозит в часы пик.
В ближайшее время мы частично решим проблему банальным апгрэйдом железа.
Параллельно мы переписываем сайт. Процесс этот не быстр, так как все люди занятые, а объем работы и их сложность огромны.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, WolfHound, Вы писали:
ANS>>>ЗЫ. У меня сложилось впечатление, что днём всё заметно медленнее работает. У тебя есть какая-то статистика? WH>>Так по тому что днем приходит много народа.
ANS>Мне это действительно интересно. Хотелось бы увидеть что-то дневное и ночное в числовом выражении. Ну, там среднее время отдачи страницы с одним /случайным/ сообщением, распределение по поколениям, процент простоя от GC.
На сейчас расклад такой.
Объем памяти (в гигах):
MS SQL 1.66
Сайт + Янус 0.3
Перл (паскуда) 0.2
Статистика памяти процесса сайта (процесс запущен 20.06.2006 в 19:01):
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
ЧВV>Авторы: ЧВV> Чистяков Влад (VladD2 )
ЧВV>Аннотация: ЧВV>Уже много сказано слов о том, что такое GC, чем он хорош и как лучше его применять. Но, наверно, очень многим хочется знать, как устроен конкретный GC. Данная статья открывает некоторые подробности устройcтва GC в .NET Framework.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>И пара вопросов: ANS>wtf is "Promoted memory" & "Promoted finalization-memory" ? ANS>И не понятно почему сумма всех поколений не равна "Bytes in all heaps"
Если я правильно понимаю, то первое — это сколько памяти занимают объекты, в последний раз перешедшие из поколения в поколение (т.е. пережившие сборку), второе — сколько то же самое, но для объектов выживших в результате финализации (т.е. помеченных на удаление при сборке, но оставшихся живими из-за необходимости вызова Finalize для них).
Второе — "Bytes in all heaps" — сколько данных реально находится в кучах, а "heap X size" — сколько памяти выделено под кучу (в куче может быть еще никем не занятая, но заранее зарезервированная память — чтобы не запрашивать систему каждый раз о доп. памяти)
Здравствуйте, fmiracle, Вы писали:
ANS>>wtf is "Promoted memory" & "Promoted finalization-memory" ?
F>Если я правильно понимаю, то первое — это сколько памяти занимают объекты, в последний раз перешедшие из поколения в поколение (т.е. пережившие сборку), второе — сколько то же самое, но для объектов выживших в результате финализации (т.е. помеченных на удаление при сборке, но оставшихся живими из-за необходимости вызова Finalize для них).
Хм. имхо, 700K — большая цифра. Кто с кодом знаком, может прокомментировать (или подтвердить что цифра нормальная)?
И еще уточнение: "promoted" включает в себя "Promoted finalization" или их нужно суммировать?
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>>>wtf is "Promoted memory" & "Promoted finalization-memory" ?
F>>Если я правильно понимаю, то первое — это сколько памяти занимают объекты, в последний раз перешедшие из поколения в поколение (т.е. пережившие сборку), второе — сколько то же самое, но для объектов выживших в результате финализации (т.е. помеченных на удаление при сборке, но оставшихся живими из-за необходимости вызова Finalize для них).
ANS>Хм. имхо, 700K — большая цифра. Кто с кодом знаком, может прокомментировать (или подтвердить что цифра нормальная)?
Все относительно.
В целом — не такая уж и большая по сравнению с 3Гб что на сервере есть (т.е. 0.023% объема памяти), но горааздо больше чем ничего, да
Не забывай — объекты не насовсем выжили, а пережили одну сборку — со временим они удалятся. Хотя, конечно, лучше избегать их (применяя явный Dispose), но это не критично.
ANS>И еще уточнение: "promoted" включает в себя "Promoted finalization" или их нужно суммировать?
Есть несколько комментариев по статье, которые появились при просмотре
1) COM+ Компоненты (ES) работают по умолчанию с включенным gcServer. Чтобы это проверить не обязательно использовать API. или через tasklist /m mscorsvr.dll (при активном COM+ комопненте мы получим dllhost.exe) или используя Process Explorer — в описании компонента будет указано что он в режиме gcServer
2) Порог срабатывания GC можно изменить, для этого есть IGCHost::SetGCStartupLimits
ЧВV>Авторы: ЧВV> Чистяков Влад (VladD2 )
ЧВV>Аннотация: ЧВV>Уже много сказано слов о том, что такое GC, чем он хорош и как лучше его применять. Но, наверно, очень многим хочется знать, как устроен конкретный GC. Данная статья открывает некоторые подробности устройcтва GC в .NET Framework.
Статья как и все статьи автора великолепна, всеобъемлюща, с доступными для понимания примерами, примерами кода, аналогиями...огромное спасибо.
Что касается работы с sos.dll, описания внутренного содержания и структуры объекта .net — в своем время очень понравилась статья и графические схемы к ней: Внутреннее устройство .NET Framework — как CLR создает объекты периода выполнения
GC .NET поддерживает три поколения 0, 1 и 2. Поколения 0 и 1 считаются эфемерными. Рождаясь, объекты попадаются в нулевое поколение. Большая их часть помирает, не дождавшись первой сборки мусора. Те из них, кто переживает первую в своей жизни сборку мусора, попадают в первое поколение. Первое поколение – это своего рода отстойник. Оно позволяет отфильтровать объекты, которые не успели умереть к моменту сборки мусора по чистой случайности. Второе поколение – это, можно сказать, дом престарелых. В нем доживают свой немалый век долгожители.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: GC в .NET
От:
Аноним
Дата:
23.06.06 06:45
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, <Аноним>, Вы писали:
ЧВV>>>Статья: ЧВV>>>GC в .NET
GC .NET поддерживает три поколения 0, 1 и 2. Поколения 0 и 1 считаются эфемерными. Рождаясь, объекты попадаются в нулевое поколение. Большая их часть помирает, не дождавшись первой сборки мусора. Те из них, кто переживает первую в своей жизни сборку мусора, попадают в первое поколение. Первое поколение – это своего рода отстойник. Оно позволяет отфильтровать объекты, которые не успели умереть к моменту сборки мусора по чистой случайности. Второе поколение – это, можно сказать, дом престарелых. В нем доживают свой немалый век долгожители.
так все же что это значит?
и там эмиреными были обозваны не только поколения но и сегменты под кучи
VD>>Этот вариант у меня показывает 1401.
N_P>1000 на 2.0 N_P>230 на 1.1 SP1 N_P>1.1 без SP под рукой нет, но там было-бы что-то типа 20.
N_P>Вопрос-то в чем ? То, что в 2.0 это поправлено — я знаю. Вопрос в том, что непонятно, как на 1.1 SP1 получается такой результат.
N_P>Возвращаясь к статье — не выходит описанной простоты. Явно ведь есть еще какой-то хитрый механизм.
Для эксперимента испытал этот код под JVM 1.5.0.06 — получил 61))
Здравствуйте, <Аноним>, Вы писали:
А>так все же что это значит? А>и там эмиреными были обозваны не только поколения но и сегменты под кучи
Эфемерные поколения размещаются в эфемерном сегменте. Соттвественно такой сегмент может быть только один. При заеме нового сегмента он автоматически становится эфемерным.
Само слово имеет значения:
1) мимолетный
2) недолговечный
3) скоропреходящий
Если это не понятно, то уточни что конкретно непонято.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
ANS>>И еще, если не затруднит, такой же скриншот но в самую "жару".
[картинки выгрызины]
Я тихо фигею от колличества сборок второго поколения и особенно сильно от времени в ГЦ. 77.88 это что-то слишком много. На предыдущей картинке этот показатель был 4.01.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Я тут подумал насчет дефрагментации LOH. Ведь ее тоже можно делать причем довольно дешево.
Правда для этого придется немного покарежить ядро винды... нужно добавить функцию что-то типа VirtualMove которая позволяет переместить некий диапозон страниц с одних виртуальных адресов на другие.
Единственное что объекты LOH придется выравнивать на начало страници. При минимальном размере объекта LOH 85К и странице в 4К оверхед по памяти будет меньше 5%.
А в ОС типа сингулярити такое шаманство нужно делать в обязательном порядке.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Я тихо фигею от колличества сборок второго поколения и особенно сильно от времени в ГЦ. 77.88 это что-то слишком много. На предыдущей картинке этот показатель был 4.01.
Сборок второго поколения вроде нормальное количество. А вот с временем в ЖЦ явный глюк. Так как буквально за минуту были доли процента. Видимо как раз попали на какую-то нехилую задержку.
А вообще, когда Перл отжирает память, то начинается задница. Надо с этим чудом что-то делать.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
А вот пункт 1 заставляет GC задуматься. Ход его мыслей приблизительно следующий: «Ага! Надо проверить лимит второго поколения. Если он превышен, то собрать его. Если нет, то проверить лимит первого поколения. Если он превышен, то собрать первое поколение. Иначе собрать только нулевое поколение».
Да-да! Две секунды на тест с миллионом объектов и более 20 минут (!) на тест с 10 миллионами!!!
..........
Но почему-то наличие объектов во втором поколении постоянно подталкивает GC к сборке мусора во втором поколении.
А это не может быть случай — что обекты 2-го поколения поднимаются при постороении графа живых обектов? Или я не правильно представляю как получаются ссылки на обекты?
Здравствуйте, RredCat, Вы писали:
RC>А это не может быть случай — что обекты 2-го поколения поднимаются при постороении графа живых обектов? Или я не правильно представляю как получаются ссылки на обекты?
Старые объекты должы попадать в первое и второе поколение и не должны учитываться при построеннии графа для нулевого поколения (и соотвественно втогое поколение не учитывается при сборе мусора в первом). Так что поднять их в память может только сборка второго поколения.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Старые объекты должы попадать в первое и второе поколение и не должны учитываться при построеннии графа для нулевого поколения (и соотвественно втогое поколение не учитывается при сборе мусора в первом). Так что поднять их в память может только сборка второго поколения.
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, Чистяков Влад (VladD2 ), Вы писали:
WH>Я тут подумал насчет дефрагментации LOH. Ведь ее тоже можно делать причем довольно дешево. WH>Правда для этого придется немного покарежить ядро винды... нужно добавить функцию что-то типа VirtualMove которая позволяет переместить некий диапозон страниц с одних виртуальных адресов на другие. WH>Единственное что объекты LOH придется выравнивать на начало страници. При минимальном размере объекта LOH 85К и странице в 4К оверхед по памяти будет меньше 5%. WH>А в ОС типа сингулярити такое шаманство нужно делать в обязательном порядке.
Весь вопрос в том, что при перемещении объекта нужно модифицировать все ссылки на него.
Re: GC в .NET
От:
Аноним
Дата:
09.10.12 11:00
Оценка:
Здравствуйте, Чистяков Влад (VladD2 ), Вы писали:
Круто! Хотя и с небольшим процентом неграмотности, как обычно.
Re[3]: GC в .NET
От:
Аноним
Дата:
09.10.12 11:24
Оценка:
Здравствуйте, icWasya, Вы писали:
W>Весь вопрос в том, что при перемещении объекта нужно модифицировать все ссылки на него.
Чувак, ты поднял тему пятилетней давности, чтобы написать это ценнейшее замечание?
Здравствуйте, Аноним, Вы писали:
А>Хотя и с небольшим процентом неграмотности, как обычно.
Эта информация бесполезна. Если нашли ошибки, сообщите о них здесь или на модератор эт рсдн ру. Тогда их можно исправить. А ошибки есть практически в любой статье значительного объема. Тексты не отличаются от программ. Последний баг всегда остается не найденным.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: GC в .NET
От:
Аноним
Дата:
27.02.14 08:41
Оценка:
в статье приводится пример работы программы
Вошли в Test1()
~A();
Выполнился Test2();
Вышли из Test1()
я не поленился и набрал код, увы результат не такой
~A(); выводиться в конце
проверял для 2.0 и 4.5 версий
в 1й увы не было возможности, т к сейчас год 2014...
Здравствуйте, Аноним, Вы писали:
А>в статье приводится пример работы программы
А>Вошли в Test1() А>~A(); А>Выполнился Test2(); А>Вышли из Test1()
А>я не поленился и набрал код, увы результат не такой А>~A(); выводиться в конце
А>проверял для 2.0 и 4.5 версий А>в 1й увы не было возможности, т к сейчас год 2014...
Попробуй компилировать в Release, некропостер-рекордсмен.
ЧВV>Авторы: ЧВV> Чистяков Влад (VladD2 )
ЧВV>Аннотация: ЧВV>Уже много сказано слов о том, что такое GC, чем он хорош и как лучше его применять. Но, наверно, очень многим хочется знать, как устроен конкретный GC. Данная статья открывает некоторые подробности устройcтва GC в .NET Framework.
Здравствуйте, enabokov, Вы писали:
E>Поясните, что за процедура "обнуление памяти".
Это когда в свежевыделенный кусок памяти инциализируется нулями. Если этот участок использовался до этого, то там остаются следы прошлой деятельности. И кстати, это должно производится с точки зрения безопасности.