[plt-scheme] Re: Continuations memory accumulation problem
It seems that I've fixed the problem with the memory leak. See
below for the changed functions.
What I've changed:
* so my `call-with-current-continuation` was not in a tail
position (it was inside a `set`, and followed by a `(void)` at the end
of the function));
* I've made the `call/cc` in tail position and moved the `set`
inside the new lambda;
* the code got uglier, and less clear; I liked the old code better,
and the fact that it was clear that the `call/cc` exits with a new
continuation.
But I still don't get it where the memory leak is from:
* all my functions are not recursive (except the `do-robot!`), and
so continuations couldn't just pile up in the context of recursive
calls;
* also there are only two continuations: the current one running,
and the one to return to when interrupting... (except maybe only the
one in `start-robot!`;)
Could someone explain this to me?
Thanks,
Ciprian.
~~~~ from this
(define (enter-robot! robot)
(define continuation-tag (robot-continuation-tag robot))
(define old-behaviour-continuation (robot-continuation robot))
(set-robot-continuation! robot #f)
(set-robot-continuation! robot
(call-with-continuation-prompt
(lambda ()
(call-with-current-continuation
old-behaviour-continuation
continuation-tag))
continuation-tag))
(void))
~~~~ to this
(define (enter-robot! robot)
(call-with-continuation-prompt
(lambda ()
(call-with-current-continuation
(lambda (new-framework-continuation)
(define old-behaviour-continuation (robot-continuation robot))
(set-robot-continuation! robot new-framework-continuation)
(old-behaviour-continuation (void)))
(robot-continuation-tag robot)))
(robot-continuation-tag robot)))
~~~~
~~~~ and everything put together
~~~~
(define (start-robot! robot)
(call-with-continuation-prompt
(lambda ()
(call-with-current-continuation
(lambda (framework-continuation)
(set-robot-continuation! robot framework-continuation)
(set! framework-continuation (void))
(exit-robot! robot)
(do-robot! robot)
(set! framework-continuation (robot-continuation robot))
(set-robot-continuation! robot #f)
(framework-continuation (void)))
(robot-continuation-tag robot)))
(robot-continuation-tag robot)))
(define (enter-robot! robot)
(call-with-continuation-prompt
(lambda ()
(call-with-current-continuation
(lambda (new-framework-continuation)
(define old-behaviour-continuation (robot-continuation robot))
(set-robot-continuation! robot new-framework-continuation)
(old-behaviour-continuation (void)))
(robot-continuation-tag robot)))
(robot-continuation-tag robot)))
(define (exit-robot! robot)
(call-with-current-continuation
(lambda (new-behaviour-continuation)
(define old-framework-continuation (robot-continuation robot))
(set-robot-continuation! robot new-behaviour-continuation)
(old-framework-continuation (void)))
(robot-continuation-tag robot)))
~~~~
On Sun, Mar 14, 2010 at 10:47 PM, Ciprian Dorin, Craciun
<ciprian.craciun at gmail.com> wrote:
> Hello all!
>
> I have a small problem with continuations, more exactly memory
> builds up and I don't seem to find the problem... (This is the first
> time I seriously play with continuations so if I'm doing something
> really stupid please bare with me...) :)
>
> So maybe someone has 5 minutes to look at my code... :)
>
> What I'm trying to do: re-implement GnuRobots for PLT Scheme.
> (Actually it's done but I have this issue with the continuations.)
>
> So how I've implemented it (the code presented is extracted from
> my real code, but this snippet actually works on itself if one wants
> to try it):
> * there is a timer that calls the `step-robots!` function; (here
> the `step-robots!` just recurses with no timeout;)
> * each robot has a behaviour (in this case `do-robot!`) function
> which should after each robot-operation yield control back to the
> framework; (this way the robot behaviour can be very easily
> implemented as a tail recursive function);
> * in order to obtain this, I first capture a continuation just
> before calling the behaviour function (in this case `do-robot!`);
> * then at each step I capture the current continuation, dive in in
> the last saved continuation from `do-robot!`;
> * when the `do-robot!` function calls `exit-robot!` (this is the
> yield function) I just save the current continuation and fall-back to
> the old one (which is just inside the stepping loop);
>
> But I'm certainly doing something wrong as memory adds up and is
> freed only after a robot dies (meaning it exits the `do-robot!`) (and
> I manually call `(collect-garbage)` inside the `step-robots!`).
> Unfortunately I don't seem to find the bug...
>
> Thanks for your time!
> Ciprian.
>
> P.S.: I intend to share the source code under GPL... :)
>
> P.P.S.: I've also attached the file because Gmail tends to wrap
> lines badly...
>
>
> ~~~~
> #lang scheme
>
>
> (define-struct robot
> (continuation continuation-tag) #:mutable)
>
> (define (create-robot)
> (make-robot (void) (make-continuation-prompt-tag)))
>
>
> (define (step-robots! robots)
>
> (for ((robot (in-list robots)))
> (cond
> ((void? (robot-continuation robot))
> (start-robot! robot))
> ((continuation? (robot-continuation robot))
> (enter-robot! robot))
> (else
> (display 'died)
> (newline))))
>
> (step-robots! robots))
>
> (define (start-robot! robot)
>
> (define continuation-tag (robot-continuation-tag robot))
>
> (set-robot-continuation! robot #f)
> (set-robot-continuation! robot
> (call-with-continuation-prompt
> (lambda ()
> (call-with-current-continuation
> (lambda (new-framework-continuation)
> (set-robot-continuation! robot new-framework-continuation)
> (exit-robot! robot)
> (do-robot! robot)
> (done-robot! robot))
> continuation-tag))
> continuation-tag))
>
> (void))
>
> (define (enter-robot! robot)
>
> (define continuation-tag (robot-continuation-tag robot))
> (define old-behaviour-continuation (robot-continuation robot))
>
> (set-robot-continuation! robot #f)
> (set-robot-continuation! robot
> (call-with-continuation-prompt
> (lambda ()
> (call-with-current-continuation
> old-behaviour-continuation
> continuation-tag))
> continuation-tag))
>
> (void))
>
> (define (exit-robot! robot)
>
> (define continuation-tag (robot-continuation-tag robot))
> (define old-framework-continuation (robot-continuation robot))
>
> (set-robot-continuation! robot #f)
> (set-robot-continuation! robot
> (call-with-current-continuation
> old-framework-continuation
> continuation-tag))
>
> (void))
>
> (define (done-robot! robot)
>
> (define old-framework-continuation (robot-continuation robot))
>
> (set-robot-continuation! robot #f)
>
> (old-framework-continuation #f))
>
> (define (do-robot! robot (steps 100000))
> (unless (zero? steps)
> (exit-robot! robot)
> (do-robot! robot (- steps 1))))
>
>
> (define robots (list (create-robot) (create-robot) (create-robot)))
>
> (step-robots! robots)
>