Norma GC estándar: mientras mantenga la referencia a una parte de la colección, todos los objetos accesibles desde sus referencias permanecen en la memoria. Entonces solo la parte de la colección que es accesible de sus referencias será mantenga, el resto será recolectado. En particular, si se refiere a los últimos 50 elementos de la lista de 100 elementos, los primeros 50 elementos se recopilarán y el resto permanecerá en la memoria.
Sin embargo, en su caso se conservarán todos los elementos de cada colección a partir de la centésima. Y el motivo es evaluación diferida. La función take
produce lazy secuencia de (en su caso) 5 elementos. El objeto de secuencia diferida en sí mismo no es una secuencia real, sino que es un objeto generador especial (aunque no es el término de Clojure, sino más bien el de Python). Cuando necesite elemento de secuencia diferida, el objeto generador lo genera y lo devuelve. Pero si no solicita el elemento, el generador simplemente mantiene referencias a todos los objetos que pueda necesitar para generar un elemento.
En su ejemplo se crean grandes vectores y piden 5 elementos de ella, y luego guardar el resultado a las variables a
, b
, c
, etc. Clojure hace grande del vector y generador objeto, señalando elemento 100a. La referencia a la colección en sí se pierde, pero la referencia al objeto del generador se guarda en el nivel superior. Nunca se evalúan los objetos del generador y, por lo tanto, nunca se hacen secuencias de 5 elementos reales. REPL se refiere a los vars a
, b
, c
, etc., estos valores se refieren a objetos generadores, y los objetos generadores se refieren a las colecciones que necesitan para producir secuencias reales de 5 elementos. Por lo tanto, todos los elementos (excepto los primeros 100 de ellos) de todas las colecciones deben permanecer en la memoria.
Por otro lado, si usted evalúa objetos generadores, producirán secuencias de 5 elementos reales y olvidarán la referencia al resto de la colección. Prueba esto:
user> (def a (gctest 1e7))
#'user/a
user> (println a)
(100 101 102 103 104)
nil
user> (def b (gctest 1e7))
#'user/b
user> (println b)
(100 101 102 103 104)
nil
user> (def c (gctest 1e7))
#'user/c
user> (println c)
(100 101 102 103 104)
nil
user> (def d (gctest 1e7))
#'user/d
user> (println d)
(100 101 102 103 104)
nil
user> (def e (gctest 1e7))
#'user/e
user> (println e)
(100 101 102 103 104)
nil
user> (def f (gctest 1e7))
#'user/f
user> (println f)
(100 101 102 103 104)
nil
user> (def g (gctest 1e7))
#'user/g
user> (println g)
(100 101 102 103 104)
nil
user> (def h (gctest 1e7))
#'user/h
user> (println h)
(100 101 102 103 104)
nil
user> (def i (gctest 1e7))
#'user/i
user> (println i)
(100 101 102 103 104)
nil
No hay OutOfMemory! Vars a
, b
, c
, etc. ahora almacenan listas reales de 5 elementos y, por lo tanto, no hay más referencias a colecciones grandes, por lo que se pueden recopilar.
Así que una vez fui demasiado flojo. Estupendo. – Falko