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

Hi, I have a memory leak and cant find where it is. My script runs on Win32, Activestate perl 633 and I have a csv file that looks like so..

Man;Server;Error;Instance;Instance_Detail;Status;CallNum<P>
The CSV file holds info on the server and what was wrong on the server as well as the call number that is associated with the event. When I have another similar event I check to see if a call already exists in the CSV file.

The code I use is this.. it works but I loose about 4k for every time I query this CSV file...

$call_num = &Check_For_Call($Man,$Server,$Error,$Instance_Detail);

sub Check_For_Call { My subroutine looks like so

my ($Man,$Server,$Error,$Instance_Detail) = @_; $num = (); $dbh = DBI->connect(qq{DBI:CSV:f_dir=$xcall_path}) or die &Debug_L +og("\nDEBUG - Problems Connecting to CSV File\n"); $dbh->{'csv_tables'}->{'Exist'} = { 'file' => 'ExistCalls', 'sep_char' => ';', 'eol' => "\n"}; my($query) = "SELECT CallNum FROM Exist where Man like '$Man' and +Server like '$Server' and Error like '$Error' and Instance_Detail lik +e '$Instance_Detail'"; #&Debug_Log("SELECT CallNum FROM Exist where Man like '$Man' and S +erver like '$Server' and Error like '$Error' and Instance_Detail like + '$Instance_Detail'\n"); my($sth) = $dbh->prepare($query) or &Debug_Log("\nDEBUG - Prob +lems Preparing the SQL Statement in Check_for_Call\n"); $num = $sth->execute() or &Debug_Log("\nDEBUG - Problems Execu +ting the SQL Statement in Check_for_Call\n"); if (defined $num) { chomp($num); $sth->finish(); $dbh->disconnect(); return ($num); } else { #No Call Number Defined $sth->finish(); $dbh->disconnect(); return (2); } $sth->finish(); $dbh->disconnect(); return(1); }

If I have a return of "1" then I know that there is no call that currently exists for the event that I received. If I get a return of "2" then I know that I have received this event before but have not received the corresponding call number yet. other wise I want to return the "call number" in the CSV file.

I do get all the correct responses from the code above I just can't let the script run without stopping and starting it every so often due to the memory leak.

Any Ideas..?

Many Thanks.

-----
Of all the things I've lost in my life, its my mind I miss the most.

Replies are listed 'Best First'.
Re: DBD::CSV Memory Leak
by Jaap (Curate) on Aug 05, 2002 at 13:25 UTC
    Turn on "use strict;" and "use warnings;" and solve all the issues it raises. Declare your variables als 'late' as possible. at the lowest possible level. If all that failes, isolate portions of the code to see if the mem leak happens there.
      I am using strict and warnings, and I get no errors or warnings in the complete code. In terms of isolating the code to find the memory leak.. I have only added the code to the origional question that is causing the mem leak. I need to verify if there is anything funny in that piece of code.

      -----
      Of all the things I've lost in my life, its my mind I miss the most.

      For what it is worth, The full code is on my scratchpad.

      -----
      Of all the things I've lost in my life, its my mind I miss the most.

        In taking a look at your scratchpad, I don't immediately see the cause of your memory leak, but I see something that should help.

        At the top of your code, you've predeclared all of your variables. This means that, regardless of where they are used, they exist. For example, you only use $hd_key in your &Setup_Config subroutine. This means that you should only declare it there, and preferably (though some argue this point) you should only declare it right before you use it. This means that all variables should have the smallest possible scope. You have, in effect, used global variables and eliminated part of the benefit of using strict. Consider the following example:

        my $foo; sub bar { # lots o' code $foo++; # more code } sub baz { # do a few laps around the pool ($foo) = (split)[2]; # shower and go home }

        In the above example, we've reused the variable $foo. For what good? Is it really necessary? This will confuse someone coming to maintain it later. Further, when the subs exit, $foo hangs around when it may not need to. Here's an example of a nice variable declaration:

        sub versive { # some pushups while ( my ($key,$value)= each %data ) { # process things } # }

        In that example, $key and $value exist only in the while loop. This means that the memory they use is available for reuse immediately after the scope of the loop ends (IIRC, the memory is not released back to the OS) and there is no worry about accidentally reusing one of those variables later and possibly having an incorrect value. If you get in the habit of coding like that, your code will be much easier to work with in the long run.

        Cheers,
        Ovid

        Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: DBD::CSV Memory Leak
by tantarbobus (Hermit) on Aug 05, 2002 at 19:34 UTC

    I played with this a bit, and it looks like DBD::CSV is what is leaking. The below code leeks ~32K/iteration, and I think the leek is originating from the execute() of a statement that has a WERE clause.

    If I drop the size of the where, clause it does not leak as much memory (removing it completely cause nothing to leak), and moving the connect & prepare out of the while(1) loop do not seem to do anything.

    What version of SQL Statement do you have? I just tried upgrading to the latest version and that fixed the problem (But the new version is much slower, alas.)

    $|++; use strict; use DBI; while(1) { my $dbh = DBI->connect("DBI:CSV:f_dir=./") or die "Cannot connect: " . $DBI::errstr; my $bob = $dbh->prepare("select * from foo where 1 = 1 OR 1=1 or 1=2 or 5.6=6 or 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 or 1 = 1 OR 1=1 or 1=2 or 5.6=6 or 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 or 1 = 1 OR 1=1 o +r 1=2 or 5.6=6 or 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 or 1 = 1 OR 1=1 or 1=2 o +r 5.6=6 or 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 o +r 6=6 or 7=7 or 9=10 or 11=23 or 1 = 1 OR 1=1 or 1=2 or 5.6=6 o +r 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 or 6=6 or 7=7 or 9=10 or 11=23 "); $bob->execute(); $bob->finish; print "."; sleep(1); }
Re: DBD::CSV Memory Leak
by AcidHawk (Vicar) on Aug 05, 2002 at 14:54 UTC
    I have moved the variables to the top of the sub as opposed to them being at the begining of the script. Still 4k per message leaks.. I'll keep looking. Thanks for the suggestions though.

    the code now looks like the following:-

    sub Check_For_Call { my ($dsm,$server,$agt,$inst_det) = @_; my $dbh = (); my $sth = (); my $query = (); $num = (); $dbh = DBI->connect(qq{DBI:CSV:f_dir=$xcall_path}) or die &Debug_L +og("\nDEBUG - Problems Connecting to CSV File\n"); $dbh->{'csv_tables'}->{'Exist'} = { 'file' => 'ExistCalls', 'sep_char' => ';', 'eol' => "\n"}; $query = "SELECT CallNum FROM Exist where Dsm like '$dsm' and Serv +er like '$server' and Agent like '$agt' and Instance_Detail like '$in +st_det'"; #&Debug_Log("SELECT CallNum FROM Exist where Dsm like '$dsm' and S +erver like '$server' and Agent like '$agt' and Instance_Detail like ' +$inst_det'\n"); $sth = $dbh->prepare($query) or &Debug_Log("\nDEBUG - Problems + Preparing the SQL Statement in Check_for_Call\n"); $num = $sth->execute() or &Debug_Log("\nDEBUG - Problems Execu +ting the SQL Statement in Check_for_Call\n"); if (defined $num) { chomp($num); $sth->finish(); $dbh->disconnect(); return ($num); } else { #No Call Number Defined $sth->finish(); $dbh->disconnect(); return (2); } $sth->finish(); $dbh->disconnect(); return(1); }

    Update: I have the use strict and use warnings at the begining of my full script at my scratchpad.

    -----
    Of all the things I've lost in my life, its my mind I miss the most.
Re: DBD::CSV Memory Leak
by Jaap (Curate) on Aug 05, 2002 at 14:30 UTC
    Where do you decalre your $dbh variable? Do it as late as possible so it it re-initialised every time the sub is called.
      I have moved the declaration of the $dhb variable to the begining of the function where I need it. So it does get re-initialised each time. Still no change to my problem.

      -----
      Of all the things I've lost in my life, its my mind I miss the most.
Re: DBD::CSV Memory Leak
by AcidHawk (Vicar) on Aug 06, 2002 at 12:16 UTC
    Thank you to those who voted and those who commented on this issue.

    I have upgraded my
    DBI module to v1.27
    DBD_CSV to v0.1023
    Text-CSV_XS to v0.21
    SQL-Statement to v1.004

    This has solved the problem of memory leaking.

    I did experience some issues compiling the code under perl2exe. I got an error with the Parse.pm on line 180 all I did was replace
    require "$mod";
    with
    require "SQL/Dialects/ANSI.pm"; require "SQL/Dialects/AnyData.pm"; require "SQL/Dialects/CSV.pm";
    Not pretty but I needed it to work fast..

    Once again Many thanks to those that looked at this, I hope I can be as much help on PerlMonks in the future.

    -----
    Of all the things I've lost in my life, its my mind I miss the most.