Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Выявление потеряных сильных ссылок на объекты, Кто и как? JIT или GAC? 
:(
    Опции темы
Абабо
Дата 16.5.2007, 12:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 14.1.2005

Репутация: нет
Всего: 1



Ребята, не подскажете, где можно найти подробное описание процесса выявления потерянных сильных ссылок на объекты в контексте стека при сборке мусора? 

Я собираюсь писать на НИРС упрощённую системку времени исполнения типа CLR для .NET Framework и хотел бы познакомиться с деталями существующих реализаций подобных сред. Стоит следующий вопрос. Сборка мусора инициируется кодом, сгенерированным JIT? Т.е. JIT Compiler так строит код, что тот сам при откате стека (выход из контекста) вычленяет потерянные ссылки и вызывает метод GAC для освобождения сильной ссылки? (Такой подход мне кажется простым и логичным). Но, может, GAC – сущность с самостоятельным поведением и каким-то образом сам распознаёт эти ссылки? (туманно и непонятно…). Короче, жду вашего совета или ссылки на соответствующий док. Спасибо. 
--------------------
С уважением, Абабо.
PM MAIL   Вверх
tol05
Дата 16.5.2007, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



Куча одна на все потоки и домены CLR процесса просто на объекты, в ней расположенные, ссылки заносятся в стек потока, так что когда стек потока очищается, то удаляются из него только ссылки на объекты, сами же объекты спокойно в куче живут.
Сборщик мусора работает в своем, отдельном, выделенном потоке и работает абсолютно автономно. Его работа не зависит от состояния потока выполнения. Когда мы в коде пишем GC.Collect(), то мы его только заставлем начать работу "вне графика".

Почитать - проблема. В основном - на английском, в блогах разных.
Ну вот что у меня есть по потокам и памяти
http://www.truemind.ru/articles/article/284.html
http://blogs.gotdotnet.ru/personal/mihaili...25-C69C8E05C7D8
http://blogs.msdn.com/yunjin/archive/2005/07/05/435726.aspx
http://www.intuit.ru/department/pl/cil/
http://blogs.msdn.com/cbrumme/archive/tags/CLR/default.aspx
http://www.microsoft.com/rus/msdn/magazine..._projection.asp
http://www.rsdn.ru/article/dotnet/GC.xml


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
Абабо
Дата 16.5.2007, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 14.1.2005

Репутация: нет
Всего: 1



Да, но необходимо же как-то и кого-то информировать о том что закрывается ссылка при выходе из стекового контекста (чтобы декрементировать счётчик открытых сильных ссылок объекта). Следовательно, этим занимается сам машинный код, сгенерированный JIT Compiler. А GAC когда пробуждается осматривает эти самые счётчики на наличие обнуления (или же его информирует об этом код или сам объект посредством какого-нибудь вызова). Я что-то неправильно понимаю? Спасибо за предыдущий ответ.
--------------------
С уважением, Абабо.
PM MAIL   Вверх
tol05
Дата 16.5.2007, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



Это нормально описано в http://www.rsdn.ru/article/dotnet/GC.xml 
можно еще Рихтера почитать "Рихтер C# via .Net" (глава 20) Алгоритм сбора мусора.

- каждое приложение имеет набор root-ов - указателей на свои ссылочные объекты.
- сборщик мусора, приступаю к работе, вообще все объекты в куче считает мусором. Он проверяет наличие и значения корней приложения если на текущий момент есть у приложения несколько корней, то GC лезет в кучу, находит по адресу корня объект и маркирует его.
- закончив проход стека, GC начинает удалять из кучи ВСЕ непромаркированные им объекты.
Ну а удаление - это отдельный вопрос 
smile

З.Ы. Пример
есть ф-ция Main() она вызывает F1(), а F1() вызывает F2()
Main перед вызовом F1() создала несколько размерных переменных в стеке и 2 объекта (корня) - obj1 и obj2. После вызова что-то еще будет делать - нам это не интересно
F1() перед вызовом F2() создала несколько размерных переменных в стеке и 3 объекта (корня) - obj3, obj4 и obj5. После вызова что-то еще будет делать - нам это не интересно
F2() создала несколько размерных переменных в стеке и 2 объекта (корня) - obj6 и obj7. obj6 отработал свое, собираемся работать с obj7 и тут проснулся GC
GC посмотрел на стек, видит там кучу размерных переменных, дружно созданных Main(), F1() и F2() и корни - ссылки на obj1-obj7. Он понял, что это корни, пропарсив сборку приложения. Смотрит по каждому, будут ли к нему обращения по стеку? к obj7 - будут. Полез в кучу, пометил. к obj1-obj5 тоже будут, когда выйдем из F2() в F1() обратно (или в Main, тем более). Их тоже пометил.
А вот к obj6 уже не будет обращений. Его не пометил.
Все, лезет в кучу и видит там только obj1-obj7. По каждой идет и если помеченная - оставляет, если нет (obj6) - к удалению ее


Это сообщение отредактировал(а) tol05 - 16.5.2007, 16:55


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
Абабо
Дата 16.5.2007, 19:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 14.1.2005

Репутация: нет
Всего: 1



Цитата
Смотрит по каждому, будут ли к нему обращения по стеку? к obj7 - будут. Полез в кучу, пометил. к obj1-obj5 тоже будут, когда выйдем из F2() в F1() обратно (или в Main, тем более). Их тоже пометил.
А вот к obj6 уже не будет обращений.


Да как он может смотреть, когда в момемнт пробуждения поток уже в некоторой функции F3, стековый контекст утерян (там уже новые данные), а ссылки на объекты стёрты? Следовательно перед выходом из функции объекты по объявленным в ней ссылкам должны быть демаркированы. Точнее, должен быть специальный вызов некоторой логики (метод GC?) для проверки наличия других ссылок на объект (декрементация счётчика ссылок и сравнения с 0) и рекурсивного просмотра графа объектов (может подготовить к удалению надо также и ссылаемые объекты, если на них нет больше ссылок). Значит, код вызова этой логики вставляется JIT Compiler в каждую функцию... Где ошибка в моих рассуждениях?

Я почитаю статьи по вашим ссылкам. Спасибо.

Это сообщение отредактировал(а) Абабо - 16.5.2007, 20:03
--------------------
С уважением, Абабо.
PM MAIL   Вверх
tol05
Дата 16.5.2007, 20:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



Цитата(Абабо @  16.5.2007,  19:58 Найти цитируемый пост)
поток уже в некоторой функции F3

Вам мало Main, F1() и F2()? уже F3() появилась?  smile 


Цитата(Абабо @  16.5.2007,  19:58 Найти цитируемый пост)
стековый контекст утерян (там уже новые данные), а ссылки на объекты стёрты

не знаю о чем Вы?
Я имею в виду стек вызовов потока, а он хранит всю информацию от точки входа в приложение. Именно поэтому как-то еще работает система безопасности доступа к коду (она ведь проверяет разрешения вверх по стеку вызовов, а не только разрешения конкретной функции?
В моем понимании стек выглядит так:
MainStart(...........      
               F1Start(...........     
                          F2Start(....!....)F2End
                                       ..........)F1End    
                            ............)MainEnd

---- Кол-во переменных в стеке ---->

Буду рад, если Вы немного просвятите меня по этому вопросу, редко приходится общаться на эти темы, может что-то и подзабыл smile


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
Абабо
Дата 16.5.2007, 21:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 14.1.2005

Репутация: нет
Всего: 1



Я тоже имею в виду стек вызовов, проще говоря, стек потока (пользовательского режима), ведь там хранятся не только адреса возвратов, но и локальные переменные, включая аргументы функций. 

Как работает стек? Вызывается функция (подпрограмма), в её теле может быть ещё один вызов (следовательно, указатель стека смещается – добавляется адрес возврата и выделяется место под аргументы и локальные переменные), и т.д. При возврате из функции происходит откат – указатель стека вновь возвращается к прежнему значению. Если сделать тот же вызов ещё раз – то процесс повторится, и все аргументы и локальные переменные прошлого вызова будут затёрты. Локальными переменными в CLR могут выступать указатели на объект. Следовательно, если не контролировать (обрабатывать) их уничтожение, то они будут безвозвратно потеряны (хотя ссылаемые объекты остаются сидеть в куче). И никакой сборщик мусора (GC) не уследит за уничтожением ссылки, тем более что он просыпается лишь эпизодически. 

Так как ссылок на объект может быть более одной, необходимо иметь счётчик их числа. Можно предположить, что для каждой переменной-ссылки, определённой в стековом контексте данной функции (её теле), перед инструкцией возврата код (не CIL, а уже машинный) декрементирует счётчик ссылаемого объекта. Когда же просыпается GC, он просматривает объекты в куче и находит те, у которых обнулён счётчик ссылок. Для каждого такого объекта он рекурсивно просматривает граф, ассоциированных им объектов, переходя по их полям-ссылкам (reference type fields) и декрементирует их счётчики (ведь хотя бы одна ссылка “погибла” - в лице ссылаемого объекта). Затем все объекты с обнулившимися счётчиками он метит в кандидаты на удаление. После итерации удаления объектов GC, наверно, производит дефрагментацию кучи для повышения производительности выделения памяти. 

Вот так я представляю себе принципы сборки мусора в средах, подобных CLR (если не вникать в детали). Подчёркиваю – я ничего не утверждаю, а лишь предполагаю (так бы я стал проектировать сборку мусора с текущим моим багажом знаний).
--------------------
С уважением, Абабо.
PM MAIL   Вверх
archeg
Дата 16.5.2007, 22:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 612
Регистрация: 6.1.2007
Где: Киев

Репутация: 11
Всего: 27



Цитата(Абабо @  16.5.2007,  21:40 Найти цитируемый пост)
Как работает стек? Вызывается функция (подпрограмма), в её теле может быть ещё один вызов (следовательно, указатель стека смещается – добавляется адрес возврата и выделяется место под аргументы и локальные переменные), и т.д. При возврате из функции происходит откат – указатель стека вновь возвращается к прежнему значению. Если сделать тот же вызов ещё раз – то процесс повторится, и все аргументы и локальные переменные прошлого вызова будут затёрты

И что с того что они будут затёрты? Они ведь уже не нужны - даже если они указывают на объекты в куче, ссылки будут удалены и при следующем проходе GC удалит эти объекты, так как на такие объкты нету сильных ссылок.


Цитата(Абабо @  16.5.2007,  21:40 Найти цитируемый пост)
Так как ссылок на объект может быть более одной, необходимо иметь счётчик их числа. Можно предположить, что для каждой переменной-ссылки, определённой в стековом контексте данной функции (её теле), перед инструкцией возврата код (не CIL, а уже машинный) декрементирует счётчик ссылаемого объекта. Когда же просыпается GC, он просматривает объекты в куче и находит те, у которых обнулён счётчик ссылок. Для каждого такого объекта он рекурсивно просматривает граф, ассоциированных им объектов, переходя по их полям-ссылкам (reference type fields) и декрементирует их счётчики (ведь хотя бы одна ссылка “погибла” - в лице ссылаемого объекта). Затем все объекты с обнулившимися счётчиками он метит в кандидаты на удаление

Насколько я понимаю, такого счетчика не существует. При каждой сборке мусора, GC проходит по всем ссылками и помечает объекты которые имеют хотя бы одну ссылку. Именно поэтому сборщик мусора достаточно медлителен. За то ему не нужно думать про уменьшение счётчика. Для увеличения производительности сборщик мусора делит объекты на 3 уровня - поколения и проводит сборку мусора в каждом поколении оддельно. Самое старшое поколение включает в себя объекты-долгожители, младшое - объекты которые только были созданы и еще не пережили сборку мусора.


Цитата(Абабо @  16.5.2007,  21:40 Найти цитируемый пост)
После итерации удаления объектов GC, наверно, производит дефрагментацию кучи для повышения производительности выделения памяти.

Точно, но сборщик создает минимум две кучи - кучу для маленьких и для больших объектов. Дефрагментация проводиться только в куче для маленьких объектов



--------------------
ИМХО задница есть универсальный интерфейс. Ибо через задницу можно сделать абсолютно ВСЕ (bash.org.ru)

Дядька всегда можно спросить в аське, если не задалбывать - не откажет smile
И вообще, на самом деле я студент, и ненавижу обращение на "Вы") Тут все свои  ;)
PM MAIL ICQ Jabber   Вверх
Абабо
Дата 16.5.2007, 22:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 14.1.2005

Репутация: нет
Всего: 1



Да, в этом есть ratio. smile Зачем хранить счётчики, если можно пробежаться по всему стеку и для каждой ссылки рекурсивно маркировать ссылаемые объекты. Тогда те, которые не будут маркированы - кандидаты на выброс. Красиво. Только одно меня здесь смущает. Для сканирования стека придётся приостановить поток-владелец... а то возможны сторонние эффекты - ведь указатель стека не стоит на месте, да и его содержимое динамически обновляется по мере выполнения кода. Значит поток GC приостанавливает проверяемый поток выполнения перед сканированием стека?
--------------------
С уважением, Абабо.
PM MAIL   Вверх
archeg
Дата 16.5.2007, 22:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 612
Регистрация: 6.1.2007
Где: Киев

Репутация: 11
Всего: 27



Цитата(Абабо @  16.5.2007,  22:33 Найти цитируемый пост)
Да, в этом есть ratio.  Зачем хранить счётчики, если можно пробежаться по всему стеку и для каждой ссылки рекурсивно маркировать ссылаемые объекты. Тогда те, которые не будут маркированы - кандидаты на выброс. Красиво. Только одно меня здесь смущает. Для сканирования стека придётся приостановить поток-владелец... а то возможны сторонние эффекты - ведь указатель стека не стоит на месте, да и его содержимое динамически обновляется по мере выполнения кода. Значит поток GC приостанавливает проверяемый поток выполнения перед сканированием стека? 

Нет, в крайнем случае не всегда(опционально - можно отключить) Он просто синхронизирует свою работу - в большинстве случаев это позволяет убрать паузу во время сборки мусора


--------------------
ИМХО задница есть универсальный интерфейс. Ибо через задницу можно сделать абсолютно ВСЕ (bash.org.ru)

Дядька всегда можно спросить в аське, если не задалбывать - не откажет smile
И вообще, на самом деле я студент, и ненавижу обращение на "Вы") Тут все свои  ;)
PM MAIL ICQ Jabber   Вверх
Абабо
Дата 16.5.2007, 23:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 14.1.2005

Репутация: нет
Всего: 1



А как обеспечить такую синхронизацию? Т.е. как GC в таком случае уверен, что те байты стека, которые он сейчас просматривает не модифицируются потоком? Например он переходит на следующее двойное слово в стеке, где по его расчётам должен быть адрес объекта, а в это время происходит прерывание таймера и проверяемый поток выполняет инструкции возврата и вызова новой функции со своим стековым контекстом. Предполагаемая ссылка модифицируется и GC обращается не туда - страничное прерывание (хотя, предывание - не проблема, можно поймать). Но может он маркирует неправильную область памяти, думая, что всё хорошо. Очевидна необходимость синхронизации... но как? В коде нету критических секций, мьютексов и прочих синхронизаторов... По любому надо в какой-то момент остановить поток (это же ведь суть синхронизации). Вопрос, как это сделать у самой границы выполнения, т.е. остановить поток только в самый необходимый момент. Может, оперативно следить за тем, чтобы указатель стека не приближался на заданное число байт к текущему месту сканирования. Но прерывания по таймеру (переключение потоков планировщиком) непредсказуемы, потому нельзя гарантировать, что указатель стека потока не пересечётся с местом сканирования...  smile 
--------------------
С уважением, Абабо.
PM MAIL   Вверх
archeg
Дата 16.5.2007, 23:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 612
Регистрация: 6.1.2007
Где: Киев

Репутация: 11
Всего: 27



Цитата(Абабо @  16.5.2007,  23:17 Найти цитируемый пост)
А как обеспечить такую синхронизацию? Т.е. как GC в таком случае уверен, что те байты стека, которые он сейчас просматривает не модифицируются потоком? 

Сложно ответить. В данном случае, синхронизация - это приостановка любого потока, который пробует изменить область данных, которую просматривает в данный момент GC. Это минипауза. Оперативно следить за тем, чтобы указатель стека не приближался на заданное число байт к текущему месту сканирования - зачем? думаю поток приостанавливается непосредственно перед изменением ссылки, с которой в данный момент работает GC. А как он перехвачивает такие потоки и останавливает, тут вопрос видимо кроеться глубоко в основах CLR. 


--------------------
ИМХО задница есть универсальный интерфейс. Ибо через задницу можно сделать абсолютно ВСЕ (bash.org.ru)

Дядька всегда можно спросить в аське, если не задалбывать - не откажет smile
И вообще, на самом деле я студент, и ненавижу обращение на "Вы") Тут все свои  ;)
PM MAIL ICQ Jabber   Вверх
archeg
Дата 17.5.2007, 00:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 612
Регистрация: 6.1.2007
Где: Киев

Репутация: 11
Всего: 27



Например перед каждым изменением ссылки JIT вставляет код проверки на то, запущен ли в данное время GC и работает ли он с этой ссылкой. Если да - поток приостанавливается до конца обратоки проблемной ссылки GC


--------------------
ИМХО задница есть универсальный интерфейс. Ибо через задницу можно сделать абсолютно ВСЕ (bash.org.ru)

Дядька всегда можно спросить в аське, если не задалбывать - не откажет smile
И вообще, на самом деле я студент, и ненавижу обращение на "Вы") Тут все свои  ;)
PM MAIL ICQ Jabber   Вверх
Абабо
Дата 17.5.2007, 08:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 14.1.2005

Репутация: нет
Всего: 1



tol05 и archeg. Спасибо за интересную беседу! smile
--------------------
С уважением, Абабо.
PM MAIL   Вверх
tol05
Дата 17.5.2007, 09:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



А я вот не хочу прерывать такую интересную беседу!  smile 
У меня всего три темы в .Net есть и эта - одна из них.

archeg, Абабо, ну почитайте вы Рихтера! я после ваших постов специально перечитал упоминаемую мной 20 главу (как воды родниковой напился  smile ). 
Там же все написано. 
Цитата(Абабо @  16.5.2007,  22:33 Найти цитируемый пост)
Значит поток GC приостанавливает проверяемый поток выполнения перед сканированием стека

Цитата(archeg @  16.5.2007,  22:58 Найти цитируемый пост)
Нет, в крайнем случае не всегда(опционально - можно отключить)


Раздел "другие вопросы производительности сборщика мусора"
Цитата

"В реальном мире весьма вероятно, что несколько потоков будут обращаться к управляемой куче или хотя бы работать с размещенными в ней объектами.
Когда в результате работы одного из потоков инициируется сбор мусора, остальные не должны обращаться ни к каким объектам (включая ссылки в собственном стеке), так как сборщик мусора может переместить эти объекты, изменив их адреса в памяти. (Мое прим. Он имеет в виду  дефрагментацию кучи после очистки от мусора)
Итак, когда сборщик начинает сбор мусора, нужно приостановить все потоки, исполняющие управляемый код..."

archeg, а как 
Цитата(archeg @  16.5.2007,  22:58 Найти цитируемый пост)
опционально - можно отключить
 ? Если знаешь, скажи. Нет, я серьезно, может Рихтер и не захотел вдаваться в эти подробности, и так материал у него сложный


По поводу маркировки и корней еще немного инфы:
Цитата

"Для каждого домена CLR строит таблицу описателей GC (GC handle table), с помощью которой приложение отслеживает время жизни объекта ...
Каждый элемент таблицы состоит из указателя на объект в управляемой куче и флага, указывающего на способ мониторинга или управления объектом"

(Мое прим. Он имеет в виду например режим отладки - дебаггинга, когда время жизни объекта искусственно увеличивается. Долго писать, да и автор это сделал лучше, чем я смогу smile Кстати, он и типы флагов описал, и их назначение)


Это сообщение отредактировал(а) tol05 - 17.5.2007, 09:22


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0558 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.