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
This commit is contained in:
parent
325600b0cf
commit
8f17913d55
|
@ -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)
|
||||
|
|
16
collects/math/tests/strictness-memory-leak-test.rkt
Normal file
16
collects/math/tests/strictness-memory-leak-test.rkt
Normal file
|
@ -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))
|
Loading…
Reference in New Issue
Block a user