сборка мусора - маркировка + уборка должны быть монолитными / атомными - PullRequest
0 голосов
/ 21 мая 2018

В этом обсуждении будет использоваться код микропифона, но, поскольку он настолько прост, я надеюсь, что он будет полезен для общего обсуждения использования mark + sweep

Micropython используетвывоз мусора, в частности разметка и подметание;давайте определим это.

garbage collection

Mark
Во время фазы mark , gcследует за ссылками на память и буквально отмечает используемые блоки памяти, чтобы указать, что они достижимы из набора корневых блоков.

Sweep
После того, как фаза пометки завершена, уборщик проходит по всей куче, и если используется блок памяти, но не отмечен , помеченный , это означает, что оннедоступен кодом, поэтому он «освобожден», т. е. помечен как free .Блоки памяти, помеченные во время фазы mark , удаляют эту метку.

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

Это поможет уменьшить дрожание: вместо одного большого удара по времени у вас будет разбросана куча меньших вызовов.(Детали реализации того, как вы «разложили» вызовы gc, здесь не обсуждаются ... если только кто-то не думает, что это добавит к обсуждению.)

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

Можно выполнить две операции: распределение и освобождение.

Распределение

Что может произойти, если пользователь выполняет выделение в середине фазы метки или развертки?

Давайте рассмотрим конкретный пример кода

>> var1 = SomeAllocation()

Распределение во время пометки
В приведенном выше примере оператор выполняется в REPL, поэтому любые добавления в словарь будут вноситься в глобальный словарь, который является записью в GC Roots.Если запись добавляется в глобальные объекты до ее сканирования, ничего «плохого» не происходит: новый блок памяти будет помечен , как и должно быть.

Проблема в том, что глобальные переменные изменены1064 * после оно было отсканировано.В этом случае блок памяти не будет помечен 1067 *, поэтому на этапе развертки он будет считаться «недоступным» и освобожденным.,,даже если это не должно быть.

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

Решение

Если gc находится в середине выполнения, пометьте выделенныйблок как помеченный .Единственным недостатком является то, что если вы выделите в фазе развертки и после того, как уборщик проверит вновь выделенный блок, вы закончите gc блоком, помеченным mark .Если пользователь явно не освободит его, вам придется пройти дополнительный цикл gc, чтобы освободить его, если он станет недоступным.

Но есть простое решение: если вы выделяете во время фазовой развертки, вы проверяете положение уборщика: если за ним стоит новый блок, который будет выделен, не помечайте его mark и в противном случае пометьте его mark , так как уборщик удалил бы mark .Таким образом, вы не выйдете из gc с блоками, помеченными mark .

Deallocation

Что может произойти, если пользователь выполнит выделение в середине любой меткиили фаза развертки?

Распределение во время отметки

Если блок освобожден до сканирования ссылочного (родительского) блока, ничего не происходит.

Если блок освобожден и у него есть дочерние элементы, которые имеютуже были помечены , у нас есть несоответствие, потому что блоки должны быть помечены , только если у них есть родительский элемент, который также помечен (или родительский * GC root),В результате эти недоступные, но помеченные блоки не будут освобождены до дополнительного цикла gc, поскольку, будучи отмеченными помеченными , эти блоки без родителей, но помеченные не будут освобождаться по фазеSweep.

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

Распределение во время развертки

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

Если блок освобожден после того, как уборщик проверит его, операция free изменяет состояние целевого блока с используется до бесплатно .

ВОПРОС

Правильн ли мой анализ: можно ли разделить отметку + убрать сборку мусора?

1 Ответ

0 голосов
/ 21 мая 2018

Да, это возможно.

Java имеет коллекционер Concurrent Mark-Sweep (CMS) с версии 1.4 (2002).Это работает аналогично тому, как вы описываете.

Если вы запускаете Jython , я думаю, что вы могли бы воспользоваться этим изначально.

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