cs: correct and imprrove heuristics for force a major GC

Use `current-memory-bytes` instead of `bytes-allocated` to determine
major GCs, because the latter doesn't include enough (perhaps missing
finalized values). For example, the repair avoids unbounded memory use
from

  (let loop ([i 0])
    (malloc 6400 'atomic-interior)
    (loop))

due to finalizers that pile up faster than they are run.
This commit is contained in:
Matthew Flatt 2019-08-29 20:36:14 -06:00
parent dd5e517e88
commit 1811193285
3 changed files with 21 additions and 9 deletions

View File

@ -2691,6 +2691,10 @@
(apply append (for/list ([i 10000]) (apply append (for/list ([i 10000])
(random-sample (range 10) 100))))))) (random-sample (range 10) 100)))))))
(parameterize ([current-pseudo-random-generator (make-pseudo-random-generator)])
(random-seed 2)
(test '#(1062645402 3593208522 3838676319 2291995347 179540564 3081399108)
pseudo-random-generator->vector (current-pseudo-random-generator)))
(test #t = 0 0) (test #t = 0 0)
(test #f = 0 (expt 2 32)) (test #f = 0 (expt 2 32))

View File

@ -1402,7 +1402,7 @@
(let* ([bstr (make-bytevector size 0)] (let* ([bstr (make-bytevector size 0)]
[p (make-cpointer bstr #f)]) [p (make-cpointer bstr #f)])
(lock-object bstr) (lock-object bstr)
(with-global-lock (the-foreign-guardian p (lambda () (unlock-object bstr)))) (unsafe-add-global-finalizer p (lambda () (unlock-object bstr)))
p)] p)]
[else [else
(raise-unsupported-error 'malloc (raise-unsupported-error 'malloc
@ -1464,7 +1464,7 @@
(poll-foreign-guardian)))) (poll-foreign-guardian))))
(define (unsafe-add-global-finalizer v proc) (define (unsafe-add-global-finalizer v proc)
(the-foreign-guardian v proc)) (with-global-lock (the-foreign-guardian v proc)))
;; ---------------------------------------- ;; ----------------------------------------
@ -1973,7 +1973,7 @@
(let* ([code (make-code proc)] (let* ([code (make-code proc)]
[cb (create-callback code)]) [cb (create-callback code)])
(lock-object code) (lock-object code)
(with-global-lock (the-foreign-guardian cb (lambda () (unlock-object code)))) (unsafe-add-global-finalizer cb (lambda () (unlock-object code)))
cb)))])) cb)))]))
;; ---------------------------------------- ;; ----------------------------------------

View File

@ -34,7 +34,8 @@
(define gc-counter 1) (define gc-counter 1)
(define log-collect-generation-radix 2) (define log-collect-generation-radix 2)
(define collect-generation-radix-mask (sub1 (bitwise-arithmetic-shift 1 log-collect-generation-radix))) (define collect-generation-radix-mask (sub1 (bitwise-arithmetic-shift 1 log-collect-generation-radix)))
(define allocated-after-major (* 32 1024 1024)) (define allocated+overhead-after-major (* 32 1024 1024))
(define non-full-gc-counter 0)
;; Called in any thread with all other threads paused. The Racket ;; Called in any thread with all other threads paused. The Racket
;; thread scheduler may be in atomic mode. In fact, the engine ;; thread scheduler may be in atomic mode. In fact, the engine
@ -51,7 +52,8 @@
(set! gc-counter (add1 this-counter))) (set! gc-counter (add1 this-counter)))
(let ([gen (cond (let ([gen (cond
[(and (not g) [(and (not g)
(>= pre-allocated (* 2 allocated-after-major))) (or (>= pre-allocated+overhead (* 2 allocated+overhead-after-major))
(>= non-full-gc-counter 10000)))
;; Force a major collection if memory use has doubled ;; Force a major collection if memory use has doubled
(collect-maximum-generation)] (collect-maximum-generation)]
[else [else
@ -63,12 +65,13 @@
[else gen]))])]) [else gen]))])])
(run-collect-callbacks car) (run-collect-callbacks car)
(collect gen) (collect gen)
(let ([post-allocated (bytes-allocated)]) (let ([post-allocated (bytes-allocated)]
[post-allocated+overhead (current-memory-bytes)])
(when (= gen (collect-maximum-generation)) (when (= gen (collect-maximum-generation))
(set! allocated-after-major post-allocated)) (set! allocated+overhead-after-major post-allocated+overhead))
(garbage-collect-notify gen (garbage-collect-notify gen
pre-allocated pre-allocated+overhead pre-time pre-cpu-time pre-allocated pre-allocated+overhead pre-time pre-cpu-time
post-allocated (current-memory-bytes) (real-time) (cpu-time))) post-allocated post-allocated+overhead (real-time) (cpu-time)))
(update-eq-hash-code-table-size!) (update-eq-hash-code-table-size!)
(poll-foreign-guardian) (poll-foreign-guardian)
(run-collect-callbacks cdr) (run-collect-callbacks cdr)
@ -80,6 +83,11 @@
;; This `set-timer` doesn't necessarily penalize the right thread, ;; This `set-timer` doesn't necessarily penalize the right thread,
;; but it's likely to penalize a thread that is allocating quickly: ;; but it's likely to penalize a thread that is allocating quickly:
(set-timer 1)) (set-timer 1))
(cond
[(= gen (collect-maximum-generation))
(set! non-full-gc-counter 0)]
[else
(set! non-full-gc-counter (add1 non-full-gc-counter))])
(void)))) (void))))
(define collect-garbage (define collect-garbage
@ -349,7 +357,7 @@
(define/who (make-phantom-bytes k) (define/who (make-phantom-bytes k)
(check who exact-nonnegative-integer? k) (check who exact-nonnegative-integer? k)
(let ([ph (create-phantom-bytes (make-phantom-bytevector k))]) (let ([ph (create-phantom-bytes (make-phantom-bytevector k))])
(when (>= (bytes-allocated) (* 2 allocated-after-major)) (when (>= (current-memory-bytes) (* 2 allocated+overhead-after-major))
(collect-garbage)) (collect-garbage))
ph)) ph))