| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > .NET для новичков > GC.Collect |
| Автор: v00d00 2.2.2009, 12:54 | ||
Кто-нибудь может объяснить как работает этот метод сборщика мусора. В приведенном ниже коде, если удалить строчку с методом GC.KeepAlive(mt); программа начинает работать так, словно мутекс не создавался.
Что делает метод GC.KeepAlive() я могу понять по документации, меня интересует как метод, который вызывается после завершения программы может препятсявовать удалению объекта сборщиком мусора? Сложилось впечатление что это деректива препроцессору... |
| Автор: v00d00 4.2.2009, 17:10 | ||
Если бы я вместо этого метода обратился к свойству объекта, эффект был бы такой же? На этапе компиляции сгенерировался бы код, запрещаюший удаление этого объекта? Ведь по идее до завершения программы переменная-указатель будет продолжать лежать на стеке?
Он делает ссылку на объект после того как он теоретически может быть уничтожен? |
| Автор: emmanuil 4.2.2009, 17:59 | ||
Если бы ты использовал объект после закрытия гл. формы, то все время работы приложения он бы не уничтожился, так как на него будет ссылка. Объекты хранятся в куче, кроме структур value type - они хранятся в стеке и уничтожаются при выходи из области видимости автоматически. GC ходит по куче, считает ссылки и ликвидирует объекты. Уничтожение проходит в несколько этапов, это прочитать нужно.
|
| Автор: v00d00 4.2.2009, 18:26 |
| Mutex mt = new Mutex(true, "BudPDMLibAdmin", out MutexWasCreated); Это строка находится выше на уровень вложенности, чем получивший управление код, следовательно переменная mt гарантированно будет лежать на стеке до завершения программы. Или сборщик видит что потом она нигде не используется и удаляет объект по ней? Если переформулировать мои вопрос, то он будет выглядеть так: Почему сборщик удаляет объект под переменной, которая все еще лежит на стеке, но не используется? Ссылка то еще живая, и умрет только по выходу управления из функции. |
| Автор: emmanuil 4.2.2009, 18:46 | ||||||
Это бы работал, если бы мутекс был структурой и хранился в стеке, тогда бы сборщик его не достал. Но он хранится в куче и поэтому сборщик его уничтожит, если на него не будет ссылок. Почитай про ссылочные типы и типы значений и про сборщик, сразу станет понятнее. |
| Автор: Partizan 4.2.2009, 18:51 | ||||
v00d00, mt не будет лежать на стеке. Объект будет создан в куче
Ага...сборщик умный... |
| Автор: PashaPash 4.2.2009, 21:14 | ||
В debug JIT продлевает время жизни переменной до ее scope - чтобы в отладке можно было посмотреть значение после последнего использования. В release время жизни значительно сокращается |
| Автор: emmanuil 5.2.2009, 05:44 | ||
На сколько я знаю, то JIT это способ компиляции и JIT компиляторы. А за временем жизни объектов следит CLR - сборщик мусора. Как с этим справляется IDE мне доподленно не известно, возможно для переменных хранит ссылки на них во время отладки для показана сведений по ним. |
| Автор: PashaPash 5.2.2009, 10:38 | ||
Насколько я знаю, сборщик мусора за временем жизни объектов не следит. Он тупо пробегается по дереву объектов начиная с корней "корням" и все, что не увидит, подметает. Перменные в стеке (ссылки), глобальные переменные, значения в регистрах - это корни. Лежит ли переменная в стеке в конкретный момент, или давно выброшена и не используется - определяется JIT. И именно JIT дает GC список смертников - GC Info. Вот краткая инструкция по наблюдению за процессом в дикой природе: http://blogs.msdn.com/yunjin/archive/2005/05/15/417569.aspx |
| Автор: WarHog 5.2.2009, 12:13 |
| В подтверждение слов PashaPash - можно посмотреть еще у Рихтера - глава 20, часть называется "Сбор мусора и отладка". Там подробно расписываются особенности работы JIT-компилятора с /debug и /optimize сборками |
| Автор: emmanuil 5.2.2009, 13:01 | ||||
Вот как раз сборщик и следит. Jit при генерации кода кроме прочего создает корни и никаких смертников не дает сборщику. Это сборщик сам определяет есть ли ссылки на объект или нет. Jit не занимается поиском смертников этим занимается как раз таки сборщик, маркирует и т.д.
Про отладку я и писал, что мне доподленно не известно, но как я и предполагал, хранит ссылки, но только не IDE а сам JIT, он генерит внутреннюю таблицу корней. |
| Автор: WarHog 5.2.2009, 13:49 |
| emmanuil, как я понимаю, при генерации машинного кода JIT-компилятор в генерируемой им внутренней таблице корней указывает диапазон байт, в котором на данный корень есть ссылки. GC, находясь в определенном месте при вызове, смотрит, какие корни действительны в этой точке вызова, а какие - нет, именно по этой таблице, генерируемой JIT-компилятором |
| Автор: v00d00 5.2.2009, 14:12 |
| Спасибо за разъяснения, на будущее запомню, когда работаем с неуправляемым кодом, объекты с ресурсами нельзя позволять удлать сборщику. И на сколько я понял метод KeepAlive на самом деле ничего не делает, просто в коде хранится смещение ссылки на стеке, которая указывает на объект, который лежит в куче...)))) так сказать для красоты |
| Автор: emmanuil 5.2.2009, 14:17 | ||||
Наверное это вопрос, а не критика. (пример из рихтера)
JIT-сгенирил все свою лабуду и корни в том числе. После вызова GC.Collect(); сборщик удалит объект (речь идет о Timer), так как при поиске ссылок он не найдет ничего. Режим отладки. JIT-сгенирил все свою лабуду и корни в том числе, плюс сгенерил еще и внутреннюю таблицу, исскуственные ссылки так сказать, чтобы при вызове GC.Collect(); сборщик увидел что есть ссылки и не удалил объект до конца метода мэин. По простому так. JIT не занимается поиском смертников, для этого и создан сборщик и он управляет жизнью объекта так сказать. |
| Автор: WarHog 5.2.2009, 14:28 | ||
emmanuil, а разве в обычном режиме таблица корней не создается? ;) |
| Автор: PashaPash 5.2.2009, 15:12 | ||||
| emmanuil, За временем жизни объекта следит GC. А что именно в данном месте кода является корнем - определяет JIT. Т.е. именно JIT при отладке продлевает время жизни переменной до конца метода. Умирает (не используется) переменная - объект потенциально может быть собран GC. GC.KeepAlive всего-лишь говорит JIT что "вот тут переменная еще используется". Вот вопрос топикастера:
Ответ на него - метод явно указывает JIT что надо продлить время жизни переменной до это этой строки. Продление времени жизни переменной вызывает продление времени жизни объекта, на который она ссылается. Человек хотел подробностей
JIT отдает сборщику указание что вот с этого места XXX больше не корень. Т.е. он определяет "не смертников" в пределах метода |
| Автор: emmanuil 5.2.2009, 16:25 |
| WarHog, а ты читай внимательнее: JIT-сгенирил все свою лабуду и корни в том числе, плюс сгенерил еще и внутреннюю таблицу, исскуственные ссылки так сказать... Таблица то создается, но одна. А в отладке создается еще и внутренняя. |
| Автор: WarHog 5.2.2009, 16:31 |
| emmanuil, эта внутренняя таблица с корнями и их байтовыми смещениями создается всегда, независимо от того, release или debug версия. это влияет только на байтовые смещения корней |
| Автор: emmanuil 5.2.2009, 16:45 | ||||||||||||||
То
то Ну а я разве говорил, что сборщик делает корни и все такое? И JIT никого не информирует. Перевел в машинный, свои дела сделал всякие, указал корни и видимости, а вот удалять или нет объект решает сам сборщик, проходит, маркирует, удаляет, а потом воскресить даже может, там он не просто тупа проходит по корням как ты говорил, проходов несколько может быть.
а вот и подробности.
|
| Автор: PashaPash 5.2.2009, 16:48 | ||
Не создается никакой таблицы "искуственных ссылок". JIT создает ровно одну таблицу вида: F0 7B | 000B reg EDI becoming live 5A | 000D reg EBX becoming live F0 42 | 0017 reg EAX becoming live 72 | 0019 reg ESI becoming live 4A | 001B reg ECX becoming live F0 03 | 0026 reg EAX becoming dead ... 06 | 0043 reg EAX becoming dead 08 | 0043 reg ECX becoming dead 10 | 0043 reg EDX becoming dead 4C | 0047 reg ECX becoming live 0E | 004D reg ECX becoming dead 30 | 004D reg ESI becoming dead F1 1B | 0060 reg EBX becoming dead 38 | 0060 reg EDI becoming dead FF | В дебаге dead в этой таблице смещаются ближе к концу - вот и весь фокус. GC работает c кодом уже после JIT, в нем нет никаких "переменных" и продлевать нечего. Есть стек и регистры и инфа от JIT корень/не корень. |
| Автор: emmanuil 5.2.2009, 16:53 | ||||||||
с термином ошибся, согласен. выражал что исскуственные ссылки.
Добавлено через 2 минуты и 25 секунд Так ты уже определись
или
Добавлено через 11 минут и 56 секунд Термином как уже говорил подобрал неудачный. Сдвиг байтов - а я назвал исскуственные ссылки. |
| Автор: PashaPash 5.2.2009, 17:06 | ||||||||||||||||
Нет, не решает. Если объект в 0 поколении, без финализера, и нет живых корней - то его удалит всегда. Есть корни или нет в конкретной точке - решает JIT. Продлевает их в debug - тоже JIT.
Приведи, пожалуйста, хоть какое-то подтверждение существования дополнительной внутренней таблицы ссылок.
Да, все отлично, используется переменная и все такое. Я как бы и не пытался это опровергнуть. Вот только спорим мы вот об этом:
Я подробно расписал как и кто справляется с "этим". Дал линк, пару раз еще тут подробно описал. А ты все еще утверждаешь что
JIT явно говорит GC что конкретный регистр (переменная) или кусок стека "не корень со строчки XXX". Говорит в терминологии alive/dead. Т.е. он натурально обманывает GC и говорит что значение в регистре - переменная ссылочного типа - живет дольше чем на самом деле должна. И не надо тут никакие внутренние временные таблицы ссылок притягивать за уши Добавлено через 1 минуту и 9 секунд Ок, пофлеймили, размяли пальцы, работаем дальше Добавлено через 3 минуты и 20 секунд
JIT видит код и до себя и после себя |
| Автор: emmanuil 5.2.2009, 17:44 | ||||
Если корень перестает быть корнем, это не занчит что именно там удалится объект. Корень это всего лишь адрес на объект в куче. ссылаться могут многие переменные на один объект. При сборе сборщик проверяет корни и маркирует. И только после это немаркированные объекты могут быть удалены. |
| Автор: PashaPash 5.2.2009, 18:24 | ||
Более точно - продлевает жизнь настоящей ссылки. Он не создает доп. копию и не создает никаких внутренних таблиц. Ссылка как лежала в регистре, так и лежит, только GC не уведомляют вовремя что регистр уже не корень.
Ну чтобы совсем точно - если в умершем корне лежала единственная ссылка на объект нулевого поколения и наступила сборка мусора [тут стандартные условия при которых объекты не удаляются] объект будет удален. Мы как бы не о сборке мусора спорим, которую все давно в рихтере прочитали. Спорим о том, почему именно переменные-ссылки и объекты, на которые они ссылаются, в дебаге доживают до конца метода, когда формально самих ссылок после последнего использования уже нет. Я утверждаю что этим занимается JIT, обманывая сборщик мусора и не показывая ему настоящее положение вещей. Ты чем-то не согласен с этим утверждением и пытаешься пропихнуть модель с внутренними таблицами и искуственными ссылками. Продолжаем.. |
| Автор: emmanuil 5.2.2009, 18:58 | ||||||||||||
Да сборщика вообще не уведомляют. Он сам проверяет корни когда ничинается сборка.
Я начал спор не поэтому, я честно сказал что доподленно незнаю как в дебаге там и почему.
И вот из-за этого тоже. ну еще раз напишу, JIT сборщику никакого списка не дает, он делает корни и видимости а сборщик уже сам там разбирается кого надо удалять а кого нет. Потом ты вроде как со всем этим согласился и плавно переместился на мою ошибочку про таблицы, но и там я ошибся только в терминологии и не вел себя как флюгер:
Дискутировать дальше не вижу смысла, так как ты уже начал из-за терминов спорить. Тема закрыта. |
| Автор: PashaPash 5.2.2009, 20:04 |
| Не надо даблквотинга. Все равно ведь флеймовая тема. Лучше вот на мой единственный вопрос на форуме ответь, про XmlSerializer :( |
| Автор: v00d00 6.2.2009, 13:16 | ||
| Не знаю, имеет ли смысл здесь еще постить, однако провел эксперимент: объявил функцию:
в релизной версии результат такой же что и от применения аналогичной функции GC.KeepAlive() Сборшик анализируте не только сегмент стека, но и сегмент кода. Это все что я хотел узнать. |
| Автор: Partizan 6.2.2009, 13:21 |
| v00d00, имхо не обман сборщика мусора, а просто сборщик мусора не будет удалять объект, потому что он реально используется... |
| Автор: emmanuil 6.2.2009, 13:27 | ||
|
| Автор: v00d00 6.2.2009, 13:29 | ||
| Да объект используется, также как и в методе GC.KeepAlive(). Собственно вот коментарий от разработчиков
|
| Автор: PashaPash 6.2.2009, 14:34 | ||
Уже много на эту тему спорили выше |