Skip to content

Unintentional value retain #247

Closed
@sorawee

Description

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.

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions