Как реализовать сборку мусора в многопоточной среде? - PullRequest
2 голосов
/ 29 декабря 2008

Как выполнить сборку мусора в программе, состоящей из нескольких потоков или процессов?

Как я могу сканировать стек из каждого из этих потоков и процессов?

Требуется ли каждому процессу своя собственная процедура сбора мусора? Является ли хорошей идеей запустить сборщик мусора в отдельном потоке / процессе от реальной программы?

Ответы [ 5 ]

7 голосов
/ 29 декабря 2008

Вы должны собрать один раз за адресное пространство. Несколько потоков работают в одном и том же адресном пространстве, поэтому необходим один GC, который позаботится об этом. Для программы, которая работает, порождая различные процессы, каждый из которых выполняется в своем собственном адресном пространстве, для каждого процесса может быть GC.

В многопоточном случае имеет смысл запускать GC как другой поток. Таким образом, вы можете управлять приоритетом этого потока, чтобы обеспечить практически бесперебойную работу всей программы. Для однопоточного процесса проще всего иметь GC, который подключается к «нормальным» подпрограммам управления памятью (в частности, к выделению), но вы можете иметь два потока - один поток для исходного процесса и поток GC - для опять же, обеспечить полугладкую производительность.

Коллекционеры «останови мир» - самые простые - пометь и смести, пометь и компактно, останови и скопируй, назови это. GC, который подключается к подпрограммам управления памятью в однопоточной программе, по своей природе является "стоп-миром". В многопоточном случае потоку GC может быть предоставлен специальные привилегии планировщиком потока (сделать его бесперебойным, как только он решит работать), что позволяет вам запускать GC «останови мир» из такого привилегированного потока.

Если GC может быть прерван мутатором (т. Е. Остальной частью программы), в частности, потому что это просто еще один поток, который вообще не получает никакой специальной обработки, вам понадобится GC, который может обрабатывать помехи мутатор. В этом случае вы смотрите на инкрементальный сборщик мусора. IGC может использоваться в однопоточной настройке подпрограмм с подключением к памяти, где он может быть прерван, то есть по таймауту, чтобы обеспечить несколько бесперебойную работу всей системы; он также может использоваться в многопоточной системе, где он просто конкурирует с другими потоками за время выполнения.

Как вы могли бы найти стек (ы) программы или всех потоков программы, я не могу вам сказать, но расположение этих структур должно быть задокументировано для каждой операционной системы. Возможно, имеет смысл взять Boehm GC и отсканировать источники на наличие подсказок.

Пока Jones / Lins отправляется вам, потратьте некоторое время на http://www.memorymanagement.org/. Для получения дополнительной информации, как сказал выше Чарли Мартин, люди в Sun провели удивительные исследования и разработки в области мусора. коллекция, как и члены и сотрудники команды IBM Jikes RVM.

Редактировать: После прочтения вашего комментария к Чарли Мартину позвольте мне дать вам гораздо более краткий совет: подключите Boem GC к вашей системе и покончите с этим . Это легко написать сборщик мусора. Почти невозможно написать сборщик мусора, который будет правильным, эффективным, быстрым, хорошо себя ведет, хорошо настроен и надежен. Используйте существующий GC и переходите к интересным частям вашего проекта. Не зацикливайтесь на GC, или, что еще хуже, используйте плохо реализованный GC, который не будет вас раздражать.

7 голосов
/ 29 декабря 2008

Большинство GC - это так называемые GC "Stop the World" - в некоторых предопределенных точках ("Gc points" - например, точки вызова, прыжки, возвраты) каждый поток проверяет, существует ли какой-либо другой поток, который хочет сделать цикл GC. Как только все потоки остановлены, цикл GC будет запущен.

Конечно, существуют и другие возможности - GC в режиме реального времени, инкрементные, параллельные (и многое другое) - поиск в Интернете (вы в основном найдете опубликованные статьи) или просто покупка книги о сборщиках

Что касается сканирования стека, есть несколько способов:

  • точное сканирование:

    • стек с тегами - вы обычно держите 2 стека - один со значениями, а другой с «тегами». Что это за теги, зависит от того, что вам нужно, но в основном это будет отметка «это ссылка» / «не ссылка»

    • стеки без тегов - в основном, если у вас есть язык со строгими типами, для которого вы можете в любой момент времени (но чаще в каждой «точке GC») знать, какие типы находятся в стеке. Я приведу пример, используемый с простым интерпретатором (я только что придумал):

no-return function XY (int):
 load_param 1 
 ipush 1
 iadd
 call Z (assume: int function Z (int, int))
 new some_object
 call Y

Если мы определим наши точки GC как call / new, то, возможно, есть 3 точки, в которых нам может понадобиться узнать типы наших стеков (при записи функции XY стек считается «пустым»):

  • вызов Z - load_param загружает параметр типа int, ipush помещает в стек целые значения типа int - 2, для нашего GC здесь ничего не нужно делать
  • new - вызов Z использует 2 целых числа из стека и помещает int
  • call Y - новая размещенная ссылка, так что теперь у нас есть int и ссылка, GC должен знать об этой ссылке

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

Есть два способа запомнить эту информацию (для не тегированного стека):

  • создать таблицу для каждой точки GC
  • сгенерировать фрагмент кода для каждой точки GC (сам фрагмент кода будет отмечать ссылочные объекты)

Что касается того, когда вы собираете эту информацию, она может быть предварительно скомпилирована или как раз вовремя.

Это также может применяться к стекам машин, но все становится немного сложнее, поскольку вам, возможно, придется отслеживать и регистры.

Вы также сможете найти в Интернете несколько хороших статей о стеках без тегов.

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

  • консервативный сбор (в отличие от точного сканирования) - где вы спрашиваете себя «это значение в стеке, интерпретируется как указатель, ссылка», если оно есть, то оно «живое». Это может, конечно, течь, если есть, например. целое число, которое выглядит как указатель (память будет освобождена, если целое число когда-либо изменится, но также может быть усеяно навсегда). Большинство сборщиков c / c ++ реализованы таким образом, поэтому ищите в этом направлении, если вам интересно.

Каждый ли процесс требует своего рутина сбора мусора?

Нет ничего, что требовало бы этого, но я бы сказал, что это обычное дело - для простоты у меня был бы другой экземпляр GC (но только один для всех потоков) для каждого из моих процессов. Я полагаю, что между процессами может быть распределитель общей памяти - единственное преимущество, которое я вижу, - это, возможно, возможность лучше управлять фрагментацией памяти (потому что вы контролируете больше памяти), но сложность (взаимодействие / синхронизация inteproces - хм), объем общих данных и отсутствие независимости становятся проблемами. Я предполагаю здесь, и у меня нет никакого реального опыта с этими видами GC (или даже если они существуют) - это просто кажется мне здравым смыслом.

Это хорошая идея запустить сборщик мусора в отдельном потоке / процессе от актуальная программа?

Ну, это зависит. Хорошей идеей было бы сохранить его в другом потоке, но от этого зависит то, хотите ли вы, чтобы ваш GC был простым («остановите мир» - все остальные потоки приостановлены, так что это практически не имеет значения в в каком потоке мы выполняем наш сборщик мусора, но он лучше, если у него есть собственный поток, или у вас есть особые требования (например, ваши потоки выполняются в режиме реального времени и не должны останавливаться на долгое время, тогда у вас будет другой сборщик мусора) использовать алгоритм реального времени / инкрементальный сборщик мусора).

Все зависит от того, что вам нужно, , но что бы вы ни делали, помните - делайте это как можно проще.

И я чуть не забыл, есть несколько отличных альтернатив написанию собственного GC с нуля - например. см. LLVM , они утверждают, что «используя эти инструменты, можно просто генерировать карты стека с точностью до типа для вашей среды выполнения всего за ~ 100 строк кода C ++». (только предварительно скомпилированный код, без поддержки генерации кода JIT, как для jet). Кроме того, вы можете взглянуть на код для некоторых виртуальных машин Java (например, PhoneME Advanced VM (CVM), и, насколько я помню, kaffe довольно читабелен).

Отказ от ответственности: однажды я реализовал (в качестве студенческого проекта) точный, остановил мир, пометил, пометил и развернул GC - все, что здесь написано, является результатом того, что я помню из опыта, и должно быть правильным, но это может не будь "лучшей практикой". Исправления приветствуются.

2 голосов
/ 29 декабря 2008

Почему вы хотите сделать свой собственный GC? Или вы просто пытаетесь узнать о GC в целом? Книга Джоунса и Линя, которую рекомендует Хрвое, довольно хороша, и статья Википедия выглядит неплохо.

Java после 1.4.2 предоставила инкрементный гибридный GC, который не вызывает остановку "остановка мира"; нам нужно было сделать это, чтобы иметь дело с ориентированной на устройства Java, например, в мире Java ME. На веб-сайте Sun java есть очень хорошая расширенная бумага .

1 голос
/ 29 декабря 2008

Вот блог для Маони Стивенс . В настоящее время она является основным разработчиком .Net GC.

Вот пост о параллельном GC , в котором говорится о том, как работает .Net GC в этом случае.

1 голос
/ 29 декабря 2008

Большинство сред GC, например Java и .NET, останавливают все потоки во время сборки мусора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...