Приводит ли вызов gc() вручную к немедленному выполнению всех финализаторов?

У меня есть код, который, как я подозреваю, вызывает утечку памяти. Поскольку код использует ccall и поддерживает важную информацию, хранящуюся внутри указателей, которые должны быть освобождены кодом, который ccalled в течение finalizers.

В моей отладке я вызываю gc(). И я хочу знать, вызовет ли это немедленное срабатывание всех finalizer, прикрепленных к объектам, которые вышли за пределы области видимости.

Ответы должны касаться только julie 0.5+.


person Lyndon White    schedule 10.06.2017    source источник


Ответы (1)


После обсуждения ответа @Isaiah (удален) я решил покопаться в некоторых внутренностях и получить некоторую ясность по этому поводу. В результате у меня есть достоверные сведения о том, что когда gc() вызывается на верхнем уровне, т. е. не в локальной области действия, можно полагаться на следующую гарантию:

если объект недоступен и вы вызываете gc(), он будет завершен

что довольно четко. Часть верхнего уровня важна, поскольку при вызове gc() в локальной области локальные ссылки могут считаться или не считаться достижимыми, даже если они больше никогда не будут использоваться.

Эта гарантия действительно скрывает некоторую неопределенность под ковром «достижимости», поскольку может быть неочевидно, достижим объект или нет, потому что среда выполнения языка может сохранять ссылки на некоторые объекты по разным причинам. Эти причины должны быть подробно задокументированы, но в настоящее время это не так. Несколько примечательных случаев, когда среда выполнения удерживает объекты:

  • Уникальный экземпляр одноэлементного типа является постоянным и никогда не будет собран или завершен;

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

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

person StefanKarpinski    schedule 12.06.2017
comment
Это отличный ответ, Стефан. Будет ли справедливо сказать, что это верно только для текущей реализации gc() и не является языковым контрактом? т. е. это поведение может измениться в будущем. Например, если и когда мы получим многопоточный сборщик мусора? - person aviks; 13.06.2017
comment
Да, если мы получим параллельный сборщик мусора, все ставки сняты, но нам, конечно, придется учитывать влияние этого. В параллельном gc есть потоки-мутаторы и потоки-сборщики, которые выполняются одновременно, поэтому не совсем понятно, что вообще означает вызов gc() в потоке-мутаторе. Потенциально его можно было бы устроить так, чтобы блокировать поток мутатора, в котором он вызывается, до тех пор, пока в потоках-сборщиках не произойдет полная коллекция. Или вместо параллельного сборщика он может вызывать алгоритм остановки мира, но тогда у нас есть две разные реализации сборщика мусора, что было бы странно. - person StefanKarpinski; 13.06.2017