Consider the following program, modified from the example in the documentation for gc-terms!
; Creates n unreachable terms of the form (+ a (+ a ...)).
> (define (unused-terms! n)
(define-symbolic* a integer?)
(let loop ([n n])
(if (<= n 1)
a
(+ a (loop (- n 1)))))
(void))
> (time (unused-terms! 50000))
cpu time: 357 real time: 365 gc time: 17
> (gc-terms!) ; Use gc-terms! to change the representation.
> (collect-garbage)
> (length (terms))
50000
Logically speaking, these 50000 terms should no longer be reachable, so (length (terms)) should ideally return 0. However, it returns 50000 because of the use of parameters (terms), which don't work well with GC. To quote the documentation of parameters (https://docs.racket-lang.org/reference/parameters.html):
as far as the memory manager is concerned, the value originally associated with a parameter through parameterize remains reachable as long the continuation is reachable, even if the parameter is mutated.
In the above example, terms (actually current-terms) is initially a parameter that holds a hash retaining its keys strongly. Even when we assign terms to a hash retaining its keys weakly, the original hash is still unfortunately retained.
One possible fix is to clear the original hash explicitly. Another possibility is to initialize/parameterize current-terms to #f and immediately mutate it to the desired value afterward.
Consider the following program, modified from the example in the documentation for
gc-terms!
Logically speaking, these 50000 terms should no longer be reachable, so
(length (terms))
should ideally return0
. However, it returns50000
because of the use of parameters (terms
), which don't work well with GC. To quote the documentation of parameters (https://docs.racket-lang.org/reference/parameters.html):In the above example,
terms
(actuallycurrent-terms
) is initially a parameter that holds a hash retaining its keys strongly. Even when we assignterms
to a hash retaining its keys weakly, the original hash is still unfortunately retained.One possible fix is to clear the original hash explicitly. Another possibility is to initialize/parameterize
current-terms
to#f
and immediately mutate it to the desired value afterward.