ch.sarath has asked for the wisdom of the Perl Monks concerning the following question:

Iam new to perl scripting.I want to know what is memory leak and how it can be eliminated in recursive functions.. any reference link will do.. thanks in advance.. this is my script

use strict; print "what is the value of i:"; chomp(my $i=<>); print"\n"; print "what is the value of j:"; chomp(my $j = <>); print "\n"; my $ackerman = &ackerman($i,$j); print "A($i,$j) = $ackerman\n"; sub ackerman{ my $i=shift; my $j = shift; if($i == 1){ undef $i; return 2**$j; } elsif($j==1){ undef $j; return &ackerman($i-1,2); } else{ return &ackerman($i-1,&ackerman($i,$j-1)); } }

Replies are listed 'Best First'.
Re: memory leak
by Athanasius (Archbishop) on Jul 27, 2013 at 06:52 UTC

    Hello ch.sarath, and welcome to the Monastery!

    It looks as though you are trying to compute a variation of the Ackermann function (note the spelling), which is notable precisely because “Its value grows rapidly, even for small inputs.” Of course you are running out of memory (that’s kind of the point!), but this has nothing to do with a memory leak, and there is no way to “eliminate” this problem when designing recursive functions. Update: Seems I was too hasty here: consider Memoization as a technique for managing these kinds of problems. Thanks to Anonymous Monk, below. Best reference on memoization I know: Chapter 3 of Higher-Order Perl by Mark Jason Dominus.

    Some additional notes:

    • You should use warnings.
    • I don’t think undef $i and undef $j are needed at all, but in any case they should be $i = 0 and $j = 0 respectively.
    • Don’t call functions with an initial & unless you have a good reason to turn off prototyping. Just use: my $ackermann = ackermann($i, $j).

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: memory leak
by McA (Priest) on Jul 27, 2013 at 06:39 UTC

    Hi,

    check out the search functionality of this site. Using search term memory leak gives rather many interesting hits.

    Besides of that: Memory leak means that memory is not released after it should be not used anymore. This happens in Perl when the reference counter doesn't drop to 0. And the cause for that are often circular references.

    In your program I can't see a memeory leak, but probably others. You will need more memory the bigger the numbers are. This is by design.

    A problem you have with Perl is, that Perl doens't give memory back to the OS. So when you check the memory consumption at the beginning and at the end of your function call you will see an increase of Perl's memory footprint. But you don't know if this memory is free for usage of later claims.

    Look for the topics mentioned by me and I'm sure you find many informations.

    Best regards
    McA

Re: memory leak
by Laurent_R (Canon) on Jul 27, 2013 at 15:38 UTC

    As far as I can say, there is no memory leak in your program. It is just using a lot of memory if $i and $j become larger than simply 4 or 5 because is is recursing very deeply.

    The quick way which might fix this program would be to replace:

    use strict; print "what is the value of i:";
    by:
    use strict; use warnings; # it would have warned you about deep recursion use Memoize; memoize ('ackerman'); print "what is the value of i:";

    BTW, your function is not the standard Ackermann function as I know it. Using a recursive form of the standard Ackermann function on values 3 and 5 (result = 253), the function is called 42438 times; with memoize, it is called only 636 times. With 3 and 6, the memoized vesion is called 1277 times, the non-memoized version 172233. But even with memoize, don't call it with large numbers.

      hi Laurent_R i tried Memoize and even then it is the same scenario for i=3 and j=4.
Re:memory leak
by Loops (Curate) on Jul 27, 2013 at 06:41 UTC
    In general you need not worry about memory management in Perl. However with recursion, you're likely referring to issues discussed here: The Current Sub in Perl 5.16.

    Also, you may find some useful information here: Improve Your Extracted Traversal.

    • As the anonymous monk below mentions, these articles are about anonymous subs which may be where you heard that recursion leaks in Perl ;o)

      However with recursion, you're likely referring to issues discussed here:

      The OP doesn't use anonymous subs, so the article doesn't apply

Re: memory leak
by Laurent_R (Canon) on Jul 28, 2013 at 11:40 UTC

    As I suspected that your program might be getting into an infinite loop, I have modified it slightly to display the iteration number, and the $i and $j variables, and to stop it after 40 iterations:

    use strict; use warnings; my ($i, $j) = @ARGV; my $acker = ackermann($i, $j); print "A($i,$j) = $acker\n"; my $iter = 0; sub ackermann{ $iter ++; my $i = shift; my $j = shift; print "Iteration $iter: i = $i, j = $j \n"; return if $iter >= 40; if($i == 1){ undef $i; return 2**$j; } elsif($j==1){ undef $j; return ackermann($i-1,2); } else{ return ackermann($i-1, ackermann($i,$j-1)); } }

    I obtain the following results:

    $ perl pseudo_acker.pl 3 4 Iteration 1: i = 3, j = 4 Iteration 2: i = 3, j = 3 Iteration 3: i = 3, j = 2 Iteration 4: i = 3, j = 1 Iteration 5: i = 2, j = 2 Iteration 6: i = 2, j = 1 Iteration 7: i = 1, j = 2 Iteration 8: i = 1, j = 4 Iteration 9: i = 2, j = 16 Iteration 10: i = 2, j = 15 Iteration 11: i = 2, j = 14 Iteration 12: i = 2, j = 13 Iteration 13: i = 2, j = 12 Iteration 14: i = 2, j = 11 Iteration 15: i = 2, j = 10 Iteration 16: i = 2, j = 9 Iteration 17: i = 2, j = 8 Iteration 18: i = 2, j = 7 Iteration 19: i = 2, j = 6 Iteration 20: i = 2, j = 5 Iteration 21: i = 2, j = 4 Iteration 22: i = 2, j = 3 Iteration 23: i = 2, j = 2 Iteration 24: i = 2, j = 1 Iteration 25: i = 1, j = 2 Iteration 26: i = 1, j = 4 Iteration 27: i = 1, j = 16 Iteration 28: i = 1, j = 65536 Iteration 29: i = 1, j = inf Iteration 30: i = 1, j = inf Iteration 31: i = 1, j = inf Iteration 32: i = 1, j = inf Iteration 33: i = 1, j = inf Iteration 34: i = 1, j = inf Iteration 35: i = 1, j = inf Iteration 36: i = 1, j = inf Iteration 37: i = 1, j = inf Iteration 38: i = 1, j = inf Iteration 39: i = 1, j = inf Iteration 40: i = 1, j = inf

    So, this is seemingly never going to end (or, rather, it will fail when you will have exhausted your memory). Trying to set $i or $j to 0, rather than undefining them, when they reach 1 yields the same result. I don't have time right now to try to figure out whether your so-called Ackermann formula is necessarily going to lead you to that or whether there is a bug somewhere in your code. I might look at it later. But I suspect that this line of code:

    return 2**$j;
    is probably not what you really want, as it is bound to explode when $i reaches 1.

    I'd suggest that you might want to use the real standard Ackermann function, which is something like this:

    sub acker { my ($m, $n) = @_; return $n + 1 if $m ==0; return acker( $m-1, 1) if $n == 0; return acker ($m - 1, acker ($m, $n - 1)); }

    But don't call it for the first of the two values larger than 3.

    Or maybe you should give us the mathematical description of your so-called Ackermann function, so that we might understand what is probably wrong in your code.

      there are many forms for Ackermanns function in this case I have used the following function A(1,j) = 2^j for j>=1, A(i,1) = A(i-1,2) for i>=2, A(i,j) = A(i-1,A(i,j-1)) for i,j>=2

        OK, I have tried reimplementing your Ackermann function, still with a limit at 40 iterations to see where we get:

        use strict; use warnings; use Math::BigInt; no warnings 'recursion'; my $iter = 0; my ($c, $d) = @ARGV; print "ackermann ( $c, $d) = ", acker($c, $d), "\n"; sub acker { my ($i, $j) = @_; $iter++; print "Iteration $iter: i = $i, j = $j \n"; return if $iter >= 40; return 2**$j if $i <= 1; return acker( $i-1, 2) if $j <= 1; return acker ($i - 1, acker ($i, $j - 1)); }

        It works for 2 and 3:

        $ perl pseudo_acker2.pl 2 3 Iteration 1: i = 2, j = 3 Iteration 2: i = 2, j = 2 Iteration 3: i = 2, j = 1 Iteration 4: i = 1, j = 2 Iteration 5: i = 1, j = 4 Iteration 6: i = 1, j = 16 ackermann ( 2, 3) = 65536

        But it ceases to work for 2 and 4:

        $ perl pseudo_acker2.pl 2 4 Iteration 1: i = 2, j = 4 Iteration 2: i = 2, j = 3 Iteration 3: i = 2, j = 2 Iteration 4: i = 2, j = 1 Iteration 5: i = 1, j = 2 Iteration 6: i = 1, j = 4 Iteration 7: i = 1, j = 16 Iteration 8: i = 1, j = 65536 ackermann ( 2, 4) = inf

        In short, your Ackermann function seems to be broken or, rather, to grow so fast as to become very quickly unmanageable.

        You could also try to use one of the big integer modules, but even then your Ackerman function is more or less unusable. Using the bigint module on values 2 and 4, you get a number with almost 20,000 digits:

        $ perl pseudo_acker2.pl 2 4 Iteration 1: i = 2, j = 4 Iteration 2: i = 2, j = 3 Iteration 3: i = 2, j = 2 Iteration 4: i = 2, j = 1 Iteration 5: i = 1, j = 2 Iteration 6: i = 1, j = 4 Iteration 7: i = 1, j = 16 Iteration 8: i = 1, j = 65536 ackermann ( 2, 4) = 20035299304068464649790723515602557504478254755697 +5141926501697371089405955631145308950613088093334810103 8234342907263181822949382118812668869506364761547029165041871916351587 +96634721944293092798208430910485599 0570159318959639524863372367203002916969592156108764948889254090805911 +45703767520850020667156370236612635 9747144807111774815880914135742720967190151836282560618091458852699826 +14142503012339110827360384376787644 9043205960379124490905707560314035076162562476031863793126484703743782 +95497561377098160461441330869211810