Аннотация:
Алгоритм работы сборщика мусора (garbage collector, далее просто GC), являющегося частью CLR, подробно описан в книге Джефри Рихтера (Jeffrey Richter) «Applied Microsoft .NET Framework Programming». Мы не будем приводить здесь столь же подробное описание этого алгоритма, но обязательно остановимся на некоторых ключевых моментах.
Если нам не помогут, то мы тоже никого не пощадим.
Если бы CLR не знал ничего о созданном без его участия потоке и не просканировал бы его стек, то указатель ptr1 был бы не найден и не расценен как «живой». В этом случае деструктор объекта, на который указывает ptr1, так же был бы вызван во время сборки мусора, то есть до вывода на консоль единицы.
Найдя «живой» указатель, сборщик мусора помечает объект, на который этот указатель указывает, как всё ещё используемый программой и запрашивает информацию о его структуре, чтобы в свою очередь просканировать уже этот объект на наличие указателей на другие объекты. И так далее, пока все указатели в программе не будут обработаны.
не ищет он на стеке чужих потоков живые указатели. он просто сканирует эти внешние к clr стеки, и все, что там есть, считает набором указателей. потому что не знает типов данных на этих стеках. и если такой "указатель" вдруг попадает в область кучи, да еще прям на обьект показывает, сборщик считает это указателем на данный обьект. и обьект зависает.
зияющая дыра это дыра таких систем. поскольку вдруг, и совершенно случайно здоровенный ваш массив, не будет удаляться произвольно долго. и ваша система вдруг застрянет.
потому на GC с внешним кодом нельзя делать серьезных приложений.
и тест нужно бы все таки делать со стратегией случайного захвата и освобождения блоков случайного размера, ну там плюс минус писят процентов от некоего характеристического размера.
если же начинается подкачка страниц, GC вообще становится не по себе, поскольку ему приходится по много раз переподкачивать все страницы куда отображается куча, когда он лазает по ссылкам, а потом их еще и восстанавливает. оттого он смертельно замирает.
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, merk, Вы писали:
M>>и тест нужно бы все таки делать со стратегией случайного захвата и освобождения блоков случайного размера, ну там плюс минус писят процентов от некоего характеристического размера.
N>Осмелюсь напомнить правила форума:
N>
N>Падоначье, медицинское, юридическое, военное, и пр. и пр. арго не допускаются.
N>Не пишите сообщения только большими или только маленькими буквами.
Если сравнить "писят" и "пятьдесят", то видно что число символов сократилось почти вдвое, в то время как смысл не был утерян!
Отличная иллюстрация преимуществ функционального программирования перед всем остальным!
А как стыкуется вот эта фраза:
"объекты, пережившие две сборки мусора, остаются в хипе навсегда и GC не занимается их дефрагментацией"
и фраза из статьи ms-help://MS.MSDNQTR.2002OCT.1033/cpguide/html/cpconautomaticmemorymanagement.htm
"If this does not reclaim enough memory, the garbage collector can perform a collection of generations 2, 1, and 0."
Т.е объект поколения 2 все же может подметен из хипа?
[quote]Для хранения объектов CLR использует хип, подобный хипу C++, за тем важным исключением, что хип CLR не фрагментирован[/quote]
Явно противоречит
[quote] Другими словами, объекты, пережившие две сборки мусора, остаются в хипе навсегда и GC не занимается их дефрагментацией.[/quote]
Так фрагментирована всё-таки куча или нет?
Никакого противоречия тут нет.
Первая фраза означает, что после сборки куча дефрагментируется и все объекты сдвигаются к началу.
Вторая, что только то, что GC просто игнорирует объекты из второго поколения.
Здравствуйте, CooLer, Вы писали:
CL>Первая фраза означает, что после сборки куча дефрагментируется и все объекты сдвигаются к началу. CL>Вторая, что только то, что GC просто игнорирует объекты из второго поколения.
Да, но всё же GC.Collect() чистит и второе поколение. Данная фраза относится к автоматическому режиму GC, когда в её работу не вмешиваются.
... << RSDN@Home 1.1 beta 1 >>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Тестовый юзер, Вы писали:
ТЮ>Т.е объект поколения 2 все же может подметен из хипа?
Вполне возможно. Судя по тестам, GC не спешит чистить второе поколение, но вполне возможны ситуации, когда это может произойти. Ни подтвердить, ни опровергнуть это нельзя, т.к. во-первых, доступные исходники Rotor'а, особенно по части GC, весьма отличаются от того что на самом деле происходит в CLR, а во-вторых, MS постоянно совершенствует CLR и возможно в версии 1.1 фреймворка что-то уже и изменилось.
... << RSDN@Home 1.1 beta 1 >>
Если нам не помогут, то мы тоже никого не пощадим.
ИТ>Авторы: ИТ> Игорь Ткачев
ИТ>Аннотация: ИТ>Алгоритм работы сборщика мусора (garbage collector, далее просто GC), являющегося частью CLR, подробно описан в книге Джефри Рихтера (Jeffrey Richter) «Applied Microsoft .NET Framework Programming». Мы не будем приводить здесь столь же подробное описание этого алгоритма, но обязательно остановимся на некоторых ключевых моментах.
class Class1
{
class TestClass
{
public override string ToString()
{
return"Test Object No " + objectNo;
}
public TestClass()
{
objectNo++;
}
static int objectNo = 0;
}
// «слабая» ссылка
WeakReference wr = new WeakReference(null);
// Возвращает ссылку на объект,
// при необходимости создаёт новый
TestClass GetRef()
{
// Если объект уже создан и всё ещё жив,
// то мы можем получить ссылку на него через Target
TestClass tc = (TestClass)wr.Target;
if (tc == null)
{
tc = new TestClass();
wr.Target = tc;
}
return tc;
}
public void Test()
{
// Получаем ссылку на объектobject obj = GetRef();
// Вызываем сборщик мусора,
// но объект не будет удалён,
// т.к. существует «сильная» ссылка obj
GC.Collect();
// Печатаем "Test Object No 1"
Console.WriteLine(GetRef());
// удаляем «сильную» ссылку
obj = null;
// Печатаем опять "Test Object No 1",
// т.к. сборщик мусора не вызывался и мы можем
// получить объект через «слабую» ссылку
Console.WriteLine(GetRef());
// Вызываем сборщик мусора ещё раз
GC.Collect();
// На этот раз печатаем "Test Object No 2",
// сборщик мусора удалил старый объект,
// и вызоа GetRef создаст новый
Console.WriteLine(GetRef());
}
}
Объясните глупому, как при вызове Console.WriteLine(GetRef()); будет вызываться
public override string ToString()
? Или что вообще будет вызываться? Другими словами: точно ли печататься вообще что-либо будет?
Здравствуйте, ynblpb, Вы писали:
Y>Объясните глупому, как при вызове Console.WriteLine(GetRef()); будет вызываться Y>
Y>public override string ToString()
Y>
Y>? Или что вообще будет вызываться? Другими словами: точно ли печататься вообще что-либо будет?
А в чём проблема? Берёт и вызывает. ToString — это метод object, а всё объекты в .NET происходят от object.
Вот что происходит в результате (TextWriter.cs из исходников Ротора):
public virtual void Write(Object value) {
if (value != null) {
IFormattable f = value as IFormattable;
if (f != null)
Write(f.ToString(null, FormatProvider));
else
Write(value.ToString());
}
}
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, ynblpb, Вы писали:
Y>Объясните глупому, как при вызове Console.WriteLine(GetRef()); будет вызываться Y>
Y>public override string ToString()
Y>
Y>? Или что вообще будет вызываться? Другими словами: точно ли печататься вообще что-либо будет?
RTFM Console.WriteLine(ojbect value):
Remarks
If value is a null reference (Nothing in Visual Basic), only the line terminator is written. Otherwise, the ToString method of value is called to produce its string representation, and the resulting string is written to the standard output stream.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Соответственно, если вы создаёте класс, использующий какие-либо ресурсы,
вы также должны реализовать этот интерфейс и метод Dispose в соответствии со следующими требованиями
(эти правила никак не обозначены в MSDN и взяты мной из комментариев к исходным текстам CLI):
— Подавлять вызов метода Finalize путём удаления ссылки на объект из Finalization Queue.
не совсем понятно, почему (для чего)
вызывая Dispose, мы уже сказали сами себе, что объект нам более не нужен. а значит и использовать его более не собираемся.
В реалицации метода Dispose очищать unmanaged ресурсы,
а среда, и garbage collector (при наличии деструктора в очереди) уже позаботятся об очищении своих корней
почему нет ?
Только на РСДН помимо ответа на вопрос, можно получить еще список орфографических ошибок и узнать что-то новое из грамматики английского языка (c) http://www.rsdn.ru/forum/cpp/4720035.1.aspx
Здравствуйте, Serjio, Вы писали:
S>не совсем понятно, почему (для чего)
S>вызывая Dispose, мы уже сказали сами себе, что объект нам более не нужен. а значит и использовать его более не собираемся. S>В реалицации метода Dispose очищать unmanaged ресурсы, S>а среда, и garbage collector (при наличии деструктора в очереди) уже позаботятся об очищении своих корней S>почему нет ?
Finalization Queue и Dispose — это два параллельных механизма. Если отработал один, то другой уже не имеет смысла. Оставление объекта в FQ приводит к тому, что он гарантированно проталкивается в следующее поколение, а следовательно в старших поколениях накапливается больше мусора, который реже чистится.
... << RSDN@Home 1.2.0 alpha rev. 771>>
Если нам не помогут, то мы тоже никого не пощадим.
ИТ>Авторы: ИТ> Игорь Ткачев
ИТ>Аннотация: ИТ>Алгоритм работы сборщика мусора (garbage collector, далее просто GC), являющегося частью CLR, подробно описан в книге Джефри Рихтера (Jeffrey Richter) «Applied Microsoft .NET Framework Programming». Мы не будем приводить здесь столь же подробное описание этого алгоритма, но обязательно остановимся на некоторых ключевых моментах.
Здравствуйте, merk, Вы писали:
M>не ищет он на стеке чужих потоков живые указатели. он просто сканирует эти внешние к clr стеки, и все, что там есть, считает набором указателей. потому что не знает типов данных на этих стеках. и если такой "указатель" вдруг попадает в область кучи, да еще прям на обьект показывает, сборщик считает это указателем на данный обьект. и обьект зависает.
Это ты про консервативный сборщик мусора говоришь что ли? Откуда информация, что сборщик мусора в CLR может вести себя таким образом?
M>потому на GC с внешним кодом нельзя делать серьезных приложений.
Что такое "GC с внешним кодом"?
M>если же начинается подкачка страниц, GC вообще становится не по себе, поскольку ему приходится по много раз переподкачивать все страницы куда отображается куча, когда он лазает по ссылкам, а потом их еще и восстанавливает. оттого он смертельно замирает.
С подкачкой страниц вообще все небыстро работает. А вот механизм поколений в GC как раз призван смягчить эту проблему.
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, merk, Вы писали:
M>>не ищет он на стеке чужих потоков живые указатели. он просто сканирует эти внешние к clr стеки, и все, что там есть, считает набором указателей. потому что не знает типов данных на этих стеках. и если такой "указатель" вдруг попадает в область кучи, да еще прям на обьект показывает, сборщик считает это указателем на данный обьект. и обьект зависает.
N>Это ты про консервативный сборщик мусора говоришь что ли? Откуда информация, что сборщик мусора в CLR может вести себя таким образом?
стеки любого внешнего, неуправляемого кода(именно я об этом и говорю) придется обрабатывать таким образом. поскольку никакой информации о том, что на нем находится — нет, а узнать можно только его начало и его текущий SP, то стек придется рассматривать как массив потенциальных указателей на ваши обьекты(если такому коду разрешается их иметь вообще). таким образом применим только такой метод.
или мы говорим о чем-то другом?
M>>потому на GC с внешним кодом нельзя делать серьезных приложений. N>Что такое "GC с внешним кодом"?
с неуправляемым, в вашей терминологии.
M>>если же начинается подкачка страниц, GC вообще становится не по себе, поскольку ему приходится по много раз переподкачивать все страницы куда отображается куча, когда он лазает по ссылкам, а потом их еще и восстанавливает. оттого он смертельно замирает. N>С подкачкой страниц вообще все небыстро работает. А вот механизм поколений в GC как раз призван смягчить эту проблему.
согласен. напускать тесты сборщику, при которых начинает подкачка — не совсем правильно. это все равно что ударить его топором по голове, ипотом смотреть как он будет шевелиться.
садизм это, откровенный садизм...
Здравствуйте, merk, Вы писали:
M>и тест нужно бы все таки делать со стратегией случайного захвата и освобождения блоков случайного размера, ну там плюс минус писят процентов от некоего характеристического размера.
> не ищет он на стеке чужих потоков живые указатели. > он просто сканирует эти внешние к clr стеки, и все, что там есть, считает набором указателей. > потому что не знает типов данных на этих стеках. > и если такой "указатель" вдруг попадает в область кучи, да еще прям на обьект показывает, > сборщик считает это указателем на данный обьект. и обьект зависает.
не совсем понятно, на стеке ведь лежат не только 4-байтные значения.
как сканировать стек считая что там лежат указатели.
проверяя четверками байт, или проверять 4 байта смещаясь на один.
в любом случае, произвольные объекты будут расцененны как живые
либо майкрософты не так поступают, либо это индусское решение
о котором микрософты не говорят, а остальные не замечают
Только на РСДН помимо ответа на вопрос, можно получить еще список орфографических ошибок и узнать что-то новое из грамматики английского языка (c) http://www.rsdn.ru/forum/cpp/4720035.1.aspx
Здравствуйте, Serjio, Вы писали: S>не совсем понятно, на стеке ведь лежат не только 4-байтные значения. S>как сканировать стек считая что там лежат указатели. S>проверяя четверками байт, или проверять 4 байта смещаясь на один. S>в любом случае, произвольные объекты будут расцененны как живые
Речь идёт об управляемом стеке. Там лежат не просто четвёрки байт, а вполне конкретные указатели или вполне конкретные цифры.
Здравствуйте, Serjio, Вы писали:
S>либо майкрософты не так поступают, либо это индусское решение S>о котором микрософты не говорят, а остальные не замечают
Потрясает обилие сорванных покровов в комментах к этой статье. То вон Мерк рассказывал, как GC считает всё в стеке внешних потоков указателями, теперь вот индусское решение вдруг проявилось.
Поясняю концепцию управляемого кода: в нем есть полные метаданные обо всём.
В частности, распределение стека тоже полностью известно JITу. В MSIL, в отличие от x86, у метода нет возможности сказать "я занимаю 25 байт стека под свои нужды". Вместо этого метод содержит полный список переменных с их типами.
JIT просматривает этот список, и строит карту стека. На этой карте размечено, где именно лежат указатели. Причем анализируются и типы переменных. То есть, если в стеке лежит структура, некоторые из полей которой — ссылки, то эти поля попадут в карту стека.
Поэтому GC не нужно гадать, что и где лежит. Он смотрит в карту, в которой всё точно написано.
В непредусмотренное место указатель попасть не может — так устроен CLR. Верификатор тщательно следит за тем, чтобы код не поместил указатель куда не надо.
Если нужно передать указатель на управляемый объект в неуправляемый код (привет, Мерк!), то придется объект "запинить". То есть явно сказать среде "мы тут отдаем указатель во внешний код, ты пожалуйста с ним ничего не делай". С этого момента GC всё равно, где именно в неуправляемой памяти разместился этот указатель. Он просто будет одним из корней, учитываемых при сканировании.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Игорь Ткачев, Вы писали:
ИТ>"Другими словами, объекты, пережившие две сборки мусора, остаются в хипе навсегда и GC не занимается их дефрагментацией."
В .net 2.0 осталась такая же стратегия сборки мусора?
Здравствуйте, AlexDP, Вы писали:
ИТ>>"Другими словами, объекты, пережившие две сборки мусора, остаются в хипе навсегда и GC не занимается их дефрагментацией."
ADP>В .net 2.0 осталась такая же стратегия сборки мусора?
В данном контексте "навсегда" имеет определённые временные рамки Нулевое поколение тоже собрается, но делается это значительно реже.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>В данном контексте "навсегда" имеет определённые временные рамки Нулевое поколение тоже собрается, но делается это значительно реже.
Второе.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
IT>>В данном контексте "навсегда" имеет определённые временные рамки Нулевое поколение тоже собрается, но делается это значительно реже.
VD>Второе.
Или второе
Если нам не помогут, то мы тоже никого не пощадим.