[racket-dev] Testing whether a procedure gets collected

From: Neil Toronto (neil.toronto at gmail.com)
Date: Sat Dec 1 21:05:31 EST 2012

Ah. It prints #f for me when I have debugging info turned on in 
DrRacket; otherwise I get #<procedure>. Must be inlining keeping it 
around or something.

The problem with either finalizers or weak boxes is that neither 
provides enough guarantees. Finalizers are never guaranteed to be run. A 
weak box may not be the only reference to a procedure value, depending 
on what optimizations are done. I'm trying to test something that's 
normally not supposed to be observable.

For now, I've got a finalizer on an array procedure that's created at 
the beginning of the 1000-line test module, and I test that the 
finalizer was run at the end. I've also got a (collect-garbage) and a 
(sleep 0) in there. It works... for now, on my machine.

Maybe a weak box containing a random closure would work. Hmm...

On 12/01/2012 06:46 PM, Robby Findler wrote:
> This prints #f for me.
>
> #lang racket
>
> (define (make-box-thing v)
>    (make-weak-box (λ (_) v)))
>
> (define bx (make-box-thing 4))
> (collect-garbage)
> (weak-box-value bx)
>
> And I guess that non-closure procedures are held onto by the modules
> they are inside. This program prints #f for me, and it seems to
> confirm that hypothesis.
>
> #lang racket
>
> (define bx
>    (parameterize ([current-namespace (make-base-namespace)])
>      (eval '(module m racket
>               (define bx (make-weak-box (λ (_) 1)))
>               (provide bx)))
>      (eval '(require 'm))
>      (eval 'bx)))
>
> (collect-garbage)
> (weak-box-value bx)
>
> Robby
>
> On Sat, Dec 1, 2012 at 7:30 PM, Neil Toronto <neil.toronto at gmail.com> wrote:
>> Honestly, because I was too rushed to try them before I had to leave this
>> morning. :D However, now that I have the chance, I've found that Typed
>> Racket doesn't support them. I can't add support using `required/typed',
>> because `Weak-Box' would have to be a polymorphic type.
>>
>> Also, they don't seem to let go of procedure values. This one's value
>> doesn't ever turn to #f no matter how many times I collect garbage:
>>
>>    (define bx (make-weak-box (λ (_) 0)))
>>
>> Thinking it might be because that lambda doesn't create a closure, I tried
>> this:
>>
>>    (define (make-box-thing v)
>>      (make-weak-box (λ (_) v)))
>>
>>    (define bx (make-box-thing 4))
>>
>> But this `bx' doesn't let go of its value, either. I can't help but think
>> I'm missing something really stupid, though.
>>
>> Neil ⊥
>>
>>
>> On 12/01/2012 10:58 AM, Robby Findler wrote:
>>>
>>> How about using a weak box instead?
>>>
>>> Robby
>>>
>>> On Sat, Dec 1, 2012 at 11:45 AM, Neil Toronto <neil.toronto at gmail.com>
>>> wrote:
>>>>
>>>> I'm getting ready to push a change to math/array that fixes a memory
>>>> leak.
>>>> I've devised a test that I think will determine whether an array's
>>>> procedure
>>>> gets collected after the array is made strict, but I don't know whether
>>>> it
>>>> works only by accident. Here it is:
>>>>
>>>>
>>>> (define: collected? : (Boxof Boolean)  (box #f))
>>>>
>>>> (define arr
>>>>     (let ([proc  (λ: ([js : Indexes]) 0)])  ; constant array
>>>>       (register-finalizer proc (λ (proc) (set-box! collected? #t)))
>>>>       (build-array #() proc)))
>>>>
>>>> (array-strict! arr)
>>>> (collect-garbage)
>>>> (sleep 0)  ; give finalizers a chance to run?
>>>> (check-true (unbox collected?))
>>>>
>>>>
>>>> This test passes for me now, but will fail if anyone else tries it. What
>>>> worries me is that (sleep 0) is apparently required, meaning that
>>>> finalizers
>>>> aren't run immediately when garbage is collected.
>>>>
>>>> How can I ensure that the finalizer for `proc' gets run before I test the
>>>> value of `collected?'?
>>>>
>>>> Neil ⊥
>>>> _________________________
>>>>    Racket Developers list:
>>>>    http://lists.racket-lang.org/dev
>>
>>


Posted on the dev mailing list.