Memory leak found, was |dump-threads| (and will-execute! :d will) + 'proof of concept'/demo source
That was the first time in many years I was aware of a memory leak scenario in a Gambit env. The leak consisted of 1) https://github.com/feeley/gambit/issues/33 that regards wills not GC:ing if you ran will-execute! on it, for a programmer that one is easily worked around, and then 2) the following problem. Apart from these two, Gambit works perfectly to my knowing. Find dump_threads.scm and dump_threads_bug_demo.scm attached. Just launch them like this: $ gsc Gambit v4.6.9
*(load "dump_threads.scm") (load "dump_threads_bug_demo.scm") (demo)* "/home/user/dump_threads.scm" "/home/user/dump_threads_bug_demo.scm" Creating 10000 threads Waiting for threads to finish Numbered objects on the heap prior to GC: 10001 - A (##gc) is made here. Numbered objects on the heap after GC: 1 - All the 10000 threads GC:ed, this is what should happen. Creating 10000 threads, while doing a bunch of dump-threads calls too Waiting for threads to finish Numbered objects on the heap prior to GC: 10003 - Now we do the same test again but while doing a bunch of dump-threads calls Numbered objects on the heap after GC: 9004 - 9000 of the 1000 threads created became resistent to ##gc and never collect = Memory leak!
What happens here is that we see how (dump-threads) invocations *makes ~90% of threads running stuck on the heap and never GC*! |dump-threads| is a really neat debug tool - so neat everybody should have a copy, that kind of level of neat - how can we make it not trash Gambit like this, but instead completely reliable? Ordinary dump-threads use example, just so you know what it is about: $ gsc Gambit v4.6.9
*(load "dump_threads.scm")* "/home/user/dump_threads.scm" *(thread-start! (make-thread (lambda () (define myvar 1234) (thread-sleep! 5) (void)) 'first-thread))* #<thread #2 first-thread> *(thread-start! (make-thread (lambda () (define myvar 5678) (thread-sleep! 5) (void)) 'second-thread))* #<thread #3 second-thread> *(thread-yield!)* *(dump-threads #t 100 100)* #<thread #1 primordial> 0 loop "dump_threads.scm"@111:32 (with-exception-catcher (lambda (... result = ##thread-void-action! exception? = #f end-condvar = '#<condition-variable #4 #f> quantum-pre = .02 loop = (lambda () (letrec ((quantum-pre (thread-quantum (current-thread)))) (thread-quantum-... thread = '#<thread #1 primordial> display-environment = #t max-head = 100 max-tail = 100 1 dump-thread "dump_threads.scm"@124:5 (out) out = (lambda () ((letrec ((loop (lambda () (letrec ((quantum-pre (thread-quantum (current-t... thread = '#<thread #1 primordial> display-environment = #t max-head = 100 max-tail = 100 2 for-each 3 (interaction) (console)@5:1 (dump-threads #t 100 100)
#<thread #2 first-thread> 0 ##thread-sleep! 1 #<procedure #5> (console)@2:60 (thread-sleep! 5) myvar = 1234 2 ##thread-start-action! #<thread #3 second-thread> 0 ##thread-sleep! 1 #<procedure #6> (console)@3:60 (thread-sleep! 5) myvar = 5678 2 ##thread-start-action!
What it does is to show all running threads including their environment. So, at least in my frame of reference, a quite central debug tool. Would be great if we could fix it. Brgds, Mikael
Afficher les réponses par date
The cause of the leak within dump-threads was ##thread-continuation-capture . With the workaround in https://github.com/feeley/gambit/issues/36 applied on it, ##thread-continuation-capture now works and thus (dump-threads) too. 2013/6/22 Mikael <mikael.rcv@gmail.com>
That was the first time in many years I was aware of a memory leak scenario in a Gambit env.
The leak consisted of 1) https://github.com/feeley/gambit/issues/33 that regards wills not GC:ing if you ran will-execute! on it, for a programmer that one is easily worked around, and then 2) the following problem.
Apart from these two, Gambit works perfectly to my knowing.
Find dump_threads.scm and dump_threads_bug_demo.scm attached. Just launch them like this:
$ gsc Gambit v4.6.9
*(load "dump_threads.scm") (load "dump_threads_bug_demo.scm") (demo)* "/home/user/dump_threads.scm" "/home/user/dump_threads_bug_demo.scm" Creating 10000 threads Waiting for threads to finish Numbered objects on the heap prior to GC: 10001 - A (##gc) is made here. Numbered objects on the heap after GC: 1 - All the 10000 threads GC:ed, this is what should happen. Creating 10000 threads, while doing a bunch of dump-threads calls too Waiting for threads to finish Numbered objects on the heap prior to GC: 10003 - Now we do the same test again but while doing a bunch of dump-threads calls Numbered objects on the heap after GC: 9004 - 9000 of the 1000 threads created became resistent to ##gc and never collect = Memory leak!
What happens here is that we see how (dump-threads) invocations *makes ~90% of threads running stuck on the heap and never GC*!
|dump-threads| is a really neat debug tool - so neat everybody should have a copy, that kind of level of neat - how can we make it not trash Gambit like this, but instead completely reliable?
Ordinary dump-threads use example, just so you know what it is about:
$ gsc Gambit v4.6.9
*(load "dump_threads.scm")* "/home/user/dump_threads.scm" *(thread-start! (make-thread (lambda () (define myvar 1234) (thread-sleep! 5) (void)) 'first-thread))* #<thread #2 first-thread> *(thread-start! (make-thread (lambda () (define myvar 5678) (thread-sleep! 5) (void)) 'second-thread))* #<thread #3 second-thread> *(thread-yield!)* *(dump-threads #t 100 100)* #<thread #1 primordial> 0 loop "dump_threads.scm"@111:32 (with-exception-catcher (lambda (... result = ##thread-void-action! exception? = #f end-condvar = '#<condition-variable #4 #f> quantum-pre = .02 loop = (lambda () (letrec ((quantum-pre (thread-quantum (current-thread)))) (thread-quantum-... thread = '#<thread #1 primordial> display-environment = #t max-head = 100 max-tail = 100 1 dump-thread "dump_threads.scm"@124:5 (out) out = (lambda () ((letrec ((loop (lambda () (letrec ((quantum-pre (thread-quantum (current-t... thread = '#<thread #1 primordial> display-environment = #t max-head = 100 max-tail = 100 2 for-each 3 (interaction) (console)@5:1 (dump-threads #t 100 100)
#<thread #2 first-thread> 0 ##thread-sleep! 1 #<procedure #5> (console)@2:60 (thread-sleep! 5) myvar = 1234 2 ##thread-start-action!
#<thread #3 second-thread> 0 ##thread-sleep! 1 #<procedure #6> (console)@3:60 (thread-sleep! 5) myvar = 5678 2 ##thread-start-action!
What it does is to show all running threads including their environment.
So, at least in my frame of reference, a quite central debug tool.
Would be great if we could fix it.
Brgds, Mikael
participants (1)
-
Mikael