batkins has asked for the wisdom of the Perl Monks concerning the following question:

A Tk app I've written has a tendency to eat memory as events are fired. Someone in the CB pointed out that this could be caused by closures in my code. Is this still a problem in 5.8? That is, will I see any significant decreases in memory usage by removing closures??

TIA,
Bill

Replies are listed 'Best First'.
Re: Garbage-collecting with closures
by perrin (Chancellor) on Feb 19, 2003 at 22:19 UTC
    Not all closures leak memory. Here's an example of a situation that does leak:
    my $foo; sub leaky { my $closure = sub { $foo++ }; }
    That will create a new copy of $foo every time and it will not get cleaned up. I don't know if 5.8 did anything to address this or not.
      Does that complain under strict? I tried the following:
      use strict; my $foo = 0; sub leaky { my $closure = sub { $foo++ }; return $closure; } my $x = leaky(); my $y = leaky(); print $y->(), $/ while $x->() < 10; ---- 1 3 5 7 9
      The output seemed to be correct ...

      ------
      We are the carpenters and bricklayers of the Information Age.

      Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        The output is correct, but it eats up memory. If you keep looping on that sub, your machine will go into swap.
      It does not leaks memory for me. Why should it?

      I tried

      my $foo; sub leaky { my $closure = sub { $foo++ }; } for (;;) {leaky}
      for quite a long time and saw usage of constant memory.

      Courage, the Cowardly Dog

        Sorry, my mistake. They have to be nested anonymous subs, like this:
        my $foo = 'asdf' x 1000; for (1..900000) { my $outer_sub = sub { my $inner_sub = sub { $foo }; } }
Re: Garbage-collecting with closures
by Aristotle (Chancellor) on Feb 19, 2003 at 22:43 UTC
    I'm not sure what the Perl version has to do with whether you remove closures; if you are leaking in closures then removing them will fix your leak irrespective of the version of Perl. Closures are not problematic per se, though - you just have to be careful with your lexicals.

    Makeshifts last the longest.

Re: Garbage-collecting with closures
by batkins (Chaplain) on Feb 20, 2003 at 02:25 UTC
    All right, suppose I pass a closure to a Tk function, as in:
    $mw->Button(-text => "text", -command => sub { print "demo closure" }) +;
    Will that also cause problems?
      That's not a closure -- it's merely an anonymous sub reference.

      This would be a closure being passed to a Tk function:

      sub make_counter { my $count = shift; sub { ++$count } } $mw->Button(-text => "count", -command => &make_counter(0)});

      That in and of itself shouldn't produce leaks -- the closure will be deconstructed along with the Button deconstruction. I would imagine you need be wary of reference cycles, however, like this (functionally meaningless):

      sub make_ref_reporter { my $thing = shift; sub { ref $thing } } $mw->Button(-text => "refthing", -command => &make_ref_reporter($mw) +);

      Matt

Re: Garbage-collecting with closures
by Elian (Parson) on Feb 20, 2003 at 14:51 UTC
    There were some refcounting bugs in versions of perl before 5.8.0 that caused closures to leak, regardless of what you did with them. That's been fixed, so far as we know, so try your code with 5.8.0 and see if you're better with it. (There is, of course, always the possibility that things have been missed--perl's a big system, and refcounting GC systems are pretty error-prone)
      Leak that perrin mentioned before was fixed in the latest development version of Perl, by patch id 18302.
      This means 5.8.0 is not enough to avoid that leak, need more recent perl.

      Courage, the Cowardly Dog