In the test, if you get unlucky and there is a gc between the definition of bx and unboxing of it then this test will pass in correctly, I think (unless build-array complains if it gets #f?)
On Sun, Dec 2, 2012 at 11:44 PM, <ntoro...@racket-lang.org> wrote: > ntoronto has updated `master' from 325600b0cf to 8f17913d55. > http://git.racket-lang.org/plt/325600b0cf..8f17913d55 > > =====[ One Commit ]===================================================== > Directory summary: > 74.0% collects/math/private/array/ > 25.9% collects/math/tests/ > > ~~~~~~~~~~ > > 8f17913 Neil Toronto <ntoro...@racket-lang.org> 2012-12-02 19:02 > : > | Fixed memory leak in making arrays strict: doing so wouldn't clear > | the reference to the original procedure, which itself could hold on > | to a lot of memory > : > A collects/math/tests/strictness-memory-leak-test.rkt > M .../math/private/array/typed-array-struct.rkt | 28 > ++++++++++++-------- > > =====[ Overall Diff ]=================================================== > > collects/math/private/array/typed-array-struct.rkt > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > --- OLD/collects/math/private/array/typed-array-struct.rkt > +++ NEW/collects/math/private/array/typed-array-struct.rkt > @@ -76,17 +76,23 @@ > > (: unsafe-build-array (All (A) (Indexes (Indexes -> A) -> (Array A)))) > (define (unsafe-build-array ds f) > - (define size (check-array-shape-size 'unsafe-build-array ds)) > - (define: data : (U #f (Vectorof A)) #f) > - (define (strict!) > - (set! data (inline-build-array-data ds (λ (js j) (f js)) A))) > - (define unsafe-proc > - (λ: ([js : Indexes]) > - (let ([data data]) > - (if data > - (unsafe-vector-ref data (unsafe-array-index->value-index ds js)) > - (f js))))) > - (Array ds size ((inst box Boolean) #f) strict! unsafe-proc)) > + ;; This box's contents get replaced when the array we're constructing is > made strict, so that > + ;; the array stops referencing f. If we didn't do this, long chains of > array computations would > + ;; keep hold of references to all the intermediate procs, which is a > memory leak. > + (let ([f (box f)]) > + (define size (check-array-shape-size 'unsafe-build-array ds)) > + ;; Sharp readers might notice that strict! doesn't check to see whether > the array is already > + ;; strict; that's okay - array-strict! does it instead, which makes the > "once strict, always > + ;; strict" invariant easier to ensure in subtypes, which we don't always > have control over > + (define (strict!) > + (let* ([old-f (unbox f)] > + [vs (inline-build-array-data ds (λ (js j) (old-f js)) A)]) > + ;; Make a new f that just indexes into vs > + (set-box! f (λ: ([js : Indexes]) > + (unsafe-vector-ref vs (unsafe-array-index->value-index > ds js)))))) > + (define unsafe-proc > + (λ: ([js : Indexes]) ((unbox f) js))) > + (Array ds size ((inst box Boolean) #f) strict! unsafe-proc))) > > (: unsafe-build-strict-array (All (A) (Indexes (Indexes -> A) -> (Array A)))) > (define (unsafe-build-strict-array ds f) > > collects/math/tests/strictness-memory-leak-test.rkt > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > --- /dev/null > +++ NEW/collects/math/tests/strictness-memory-leak-test.rkt > @@ -0,0 +1,16 @@ > +#lang racket > + > +(require math/array > + rackunit) > + > +;; Make a procedure that returns a random value to keep the optimizer from > converting it to a > +;; top-level, non-closure; if that happens, the module keeps a reference to > it, which makes this > +;; test always fail > +(define bx (make-weak-box (let ([v (random)]) (λ (js) v)))) > + > +(define arr (build-array #() (weak-box-value bx))) > + > +;; Making `arr' strict should release the only remaining reference to the > contents of `bx' > +(array-strict! arr) > +(collect-garbage) > +(check-false (weak-box-value bx)) _________________________ Racket Developers list: http://lists.racket-lang.org/dev