В основном, применяются обычные правила GC ... Последовательность - это просто объект, и удерживание за его голову означает удерживание ссылки на этот объект. Это влечет за собой сохранение в памяти столько последовательности, сколько уже было реализовано, поскольку последовательности Clojure кэшируются.
(более подробное объяснение приведено ниже - см. Фрагмент, выделенный жирным шрифтом;; -))
'Последовательность' в Clojure - это объект, который реализует интерфейс ISeq. Это обеспечивает методы, которые извлекают первый элемент последовательности и остальную часть последовательности (другой объект, реализующий ISeq). В качестве ключевой детали они заботятся не только о том, чтобы вычислить правильный объект (первый / остаток последовательности) и вернуть его вызывающей стороне, но также и о кэшировании вычисленного значения в памяти, чтобы любые последующие запросы выполнялись быстрее - и, более того, важно, чтобы все запросы на один и тот же элемент последовательности гарантированно возвращали одно и то же значение, даже если ISeq генерируется поверх изменяемого объекта Java, который изменяется в какой-то момент. (Обратите внимание, что это абсолютно важно для неизменной семантики последовательностей Clojure.)
С другой стороны, Var - это контейнер, который в грубых выражениях содержит «указатель» на некоторый объект Java. Если это ISeq, то , если сам Var не является сборщиком мусора (чего, очевидно, никогда не будет, если это var верхнего уровня в существующем в настоящее время пространстве имен) или отскок, сам ISeq не будет собирать мусор и, в частности, память, которую он использует для кэширования первой / оставшейся части последовательности, не будет освобождена .
Что касается других элементов последовательности: «остаток» ISeq, связанный с Var, сам является ISeq. Кроме того, он кэшируется первым ISeq. Таким образом, первый элемент «остального» ISeq ISeq, привязанного к Var, никогда не будет собирать мусор, потому что ссылка на него удерживается «остальным» ISeq ISeq, привязанного к Var, и этот ISeq не будет быть GC'd, потому что он кэшируется как компонент rest объектом ISeq, связанным с Var, который, в свою очередь, не будет GC'd, пока он связан с Var, который, в свою очередь, обычно никогда не будет GC'd, потому что это Var верхнего уровня в пространстве имен.
Очевидно, что Var будет быть GC'd, если он перестает удерживаться его пространством имен (ns-unmap
) или само пространство имен отбрасывается (remove-ns
). Если случится, что он содержит ISeq, то этот ISeq будет GC'd, если и только если он не удерживается каким-либо другим фрагментом кода - конечно, применяются обычные правила GC. Для привязок, введенных с binding
, и локальных привязок, введенных с let
, все вышеизложенное относится к модулям проблем времени жизни привязок. (Которые не являются предметом этого вопроса.)