Почему Lua использует сборщик мусора вместо подсчета ссылок?

Я слышал и испытал это сам: сборщик мусора Lua может привести к серьезным падениям FPS в играх по мере того, как их сценарий растет.

Это, как я выяснил, связан с сборщиком мусора, где, например, каждый временно созданный объект Vector(), который создается временно, находится вокруг до сбора мусора.

Я знаю, что Python использует подсчет ссылок, и поэтому ему не нужны какие-либо огромные шаги по производительности, такие как Luas GC.

  • Почему Lua не использует подсчет ссылок, чтобы избавиться от мусора?

Ответы

Ответ 1

Поскольку подсчет ссылок сборщиков мусора может легко протекать по объектам.

Тривиальный пример: двусвязный список. Каждый node имеет указатель на следующий node - и сам на него указывает следующий. Если вы просто не ссылаетесь на сам список и ожидаете, что он будет собран, вы просто просочитесь в весь список - ни один из узлов не будет иметь счетчик ссылок, равный нулю, и, следовательно, все они будут поддерживать друг друга в живых. С помощью счетного сборщика мусора каждый раз, когда у вас есть циклический объект, вам в основном нужно рассматривать это как неуправляемый объект и явно распоряжаться им самостоятельно, когда вы закончите.

Обратите внимание, что Python использует правильный сборщик мусора в дополнение к подсчету ссылок.

Ответ 2

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

Lua 5.1 Руководство по сборке мусора

Ответ 3

Какая версия Lua используется в играх, на которых вы основываете это требование? Когда World of Warcraft переключился с Lua 5.0 на 5.1, все проблемы с производительностью, вызванные сбором мусора, были серьезно уменьшены.

С сборкой мусора Lua 5.0 количество времени, затрачиваемого на сбор мусора (и блокирование чего-либо еще от происходящего в то же время), было пропорционально количеству используемой памяти, что привело к большим усилиям, чтобы свести к минимуму использование памяти WoW.

С сборкой мусора Lua 5.1 сборщик изменился на инкрементный, поэтому он не блокирует игру, когда собирал мусор, как это делалось ранее. Теперь сбор мусора оказывает минимальное влияние на производительность по сравнению с более крупной проблемой ужасно неэффективного кода в большинстве созданных пользователем аддонов.

Ответ 4

Только подсчет ссылок недостаточно для того, чтобы сборщик мусора работал правильно, потому что он не обнаруживает циклы. Даже Python не использует подсчет ссылок в одиночку.

Представьте, что объекты A и B содержат ссылку друг на друга. Даже после того, как вы, программист больше не ссылаетесь на какой-либо объект, подсчет ссылок все равно скажет, что объекты A и B имеют ссылки, указывающие на них.

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

Ответ 5

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

Ответ 6

Вас также может заинтересовать Lua Gem об оптимизации, в котором также есть часть, которая обрабатывает сборку мусора.

Ответ 7

Взгляните на некоторые из источников CPython. Хорошая часть кода C - Py_DECREF и Py_INCREF. Это неприятное, утомительное и подверженное ошибкам книгохранилище просто уходит в Луа.

Если требуется, вам нечего мешать писать модули Lua в C, которые управляют любыми тяжелыми частными распределениями вручную.

Ответ 8

Это компромисс. Люди объяснили некоторые причины некоторыми языками (это действительно не имеет никакого отношения к Lua) используют коллекционеры, но не затронули недостатки.

Некоторые языки, в частности ObjC, используют исключительно подсчет ссылок. Огромное преимущество этого заключается в том, что освобождение является детерминированным - как только вы отпустите последнюю ссылку, он гарантирует, что объект будет немедленно освобожден. Это имеет решающее значение, если у вас есть ограничения памяти. С распределителем Lua, если ограничения памяти требуют предсказуемого освобождения, вам нужно добавить методы, чтобы немедленно освободить базовое хранилище, что наносит ущерб точке сбора мусора.

"WuHoUnited" неправильно говорит, что вы не можете этого сделать - он отлично работает с ObjC на iOS и с shared_ptr на С++. Вам просто нужно понять окружающую среду, в которой вы находитесь, избежать циклов или сломать их, когда это необходимо.