Alex Rivera | Logout

In Perl, how can I release memory to the operating system?

Asked 2009-08-07T04:00:58.070
13

I am having some problems with memory in Perl. When I fill up a big hash, I can not get the memory to be released back to the OS. When I do the same with a scalar and use undef, it will give the memory back to the OS.

Here is a test program I wrote.

#!/usr/bin/perl
###### Memory test
######

## Use Commands
use Number::Bytes::Human qw(format_bytes);
use Data::Dumper;
use Devel::Size qw(size total_size);

## Create Varable
my $share_var;
my %share_hash;
my $type_hash = 1;
my $type_scalar = 1;

## Start Main Loop
while (true) {
    &Memory_Check();
    print "Hit Enter (add to memory): "; <>;
    &Up_Mem(100_000);
    &Memory_Check();

    print "Hit Enter (Set Varable to nothing): "; <>;
    $share_var = "";
    $share_hash = ();
    &Memory_Check();

    print "Hit Enter (clean data): "; <>;
    &Clean_Data();
    &Memory_Check();

    print "Hit Enter (start over): "; <>;
}

exit;


#### Up Memory
sub Up_Mem {
    my $total_loops = shift;
    my $n = 1;
    print "Adding data to shared varable $total_loops times\n";

    until ($n > $total_loops) {
        if ($type_hash) {
            $share_hash{$n} = 'X' x 1111;
        }
        if ($type_scalar) {
            $share_var .= 'X' x 1111;
        }
        $n += 1;
    }
    print "Done Adding Data\n";
}

#### Clean up Data
sub Clean_Data {
    print "Clean Up Data\n";

    if ($type_hash) {
        ## Method to fix hash (Trying Everything i can think of!
        my $n = 1;
        my $total_loops = 100_000;
        until ($n > $total_loops) {
            undef $share_hash{$n};
            $n += 1;
        }

        %share_hash = ();
        $share_hash = ();
        undef $share_hash;
        undef %share_hash;
    }
    if ($type_scalar) {
        undef $share_var;
    }
}

#### Check Memory Usage
sub Memory_Check {
    ## Get current memory from shell
    my @mem = `ps aux | grep \"$$\"`;
    my($results) = grep !/gre
Edit
Report

1 Answer

19

Generally, yeah, that's how memory management on UNIX works. If you are using Linux with a recent glibc, and are using that malloc, you can return free'd memory to the OS. I am not sure Perl does this, though.

If you want to work with large datasets, don't load the whole thing into memory, use something like BerkeleyDB:

https://metacpan.org/pod/BerkeleyDB

Example code, stolen verbatim:

  use strict ;
  use BerkeleyDB ;

  my $filename = "fruit" ;
  unlink $filename ;
  tie my %h, "BerkeleyDB::Hash",
              -Filename => $filename,
              -Flags    => DB_CREATE
      or die "Cannot open file $filename: $! $BerkeleyDB::Error\n" ;

  # Add a few key/value pairs to the file
  $h{apple}  = "red" ;
  $h{orange} = "orange" ;
  $h{banana} = "yellow" ;
  $h{tomato} = "red" ;

  # Check for existence of a key
  print "Banana Exists\n\n" if $h{banana} ;

  # Delete a key/value pair.
  delete $h{apple} ;

  # print the contents of the file
  while (my ($k, $v) = each %h)
    { print "$k -> $v\n" }

  untie %h ;

(OK, not verbatim. Their use of use vars is ... legacy ...)

You can store gigabytes of data in a hash this way, and you will only use a tiny bit of memory. (Basically, whatever BDB's pager decides to keep in memory; this is controllable.)

answered 2009-08-07T04:11:30.967

Your Answer