Подтвердить что ты не робот

В Perl, как я могу освободить память для операционной системы?

У меня возникают проблемы с памятью в Perl. Когда я заполняю большой хэш, я не могу вернуть память обратно в ОС. Когда я делаю то же самое со скаляром и использую undef, он вернет память ОС.

Вот тестовая программа, которую я написал.

#!/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 !/grep/, @mem;

    ## Parse Data from Shell
    chomp $results;
    $results =~ s/^\w*\s*\d*\s*\d*\.\d*\s*\d*\.\d*\s*//g; $results =~ s/pts.*//g;
    my ($vsz,$rss) = split(/\s+/,$results);

    ## Format Numbers to Human Readable
    my $h = Number::Bytes::Human->new();
    my $virt = $h->format($vsz);
    my $h = Number::Bytes::Human->new();
    my $res = $h->format($rss);

    print "Current Memory Usage: Virt: $virt  RES: $res\n";

    if ($type_hash) {
        my $total_size = total_size(\%share_hash);
        my @arr_c = keys %share_hash;
        print "Length of Hash: " . ($#arr_c + 1) . "  Hash Mem Total Size: $total_size\n";
    }
    if ($type_scalar) {
        my $total_size = total_size($share_var);
        print "Length of Scalar: " . length($share_var) . "  Scalar Mem Total Size: $total_size\n";
    }

}

ВЫВОД:

./Memory_Undef_Simple.cgi 
Current Memory Usage: Virt: 6.9K  RES: 2.7K
Length of Hash: 0  Hash Mem Total Size: 92
Length of Scalar: 0  Scalar Mem Total Size: 12
Hit Enter (add to memory): 
Adding data to shared varable 100000 times
Done Adding Data
Current Memory Usage: Virt: 228K  RES: 224K
Length of Hash: 100000  Hash Mem Total Size: 116813243
Length of Scalar: 111100000  Scalar Mem Total Size: 111100028
Hit Enter (Set Varable to nothing): 
Current Memory Usage: Virt: 228K  RES: 224K
Length of Hash: 100000  Hash Mem Total Size: 116813243
Length of Scalar: 0  Scalar Mem Total Size: 111100028
Hit Enter (clean data): 
Clean Up Data
Current Memory Usage: Virt: 139K  RES: 135K
Length of Hash: 0  Hash Mem Total Size: 92
Length of Scalar: 0  Scalar Mem Total Size: 24
Hit Enter (start over): 

Итак, вы можете видеть, что память опускается, но она уменьшает размер скаляра. Любые идеи, как освободить память хеша?

Также Devel::Size показывает, что хеш занимает всего 92 байта, хотя программа все еще использует 139K.

4b9b3361

Ответ 1

Как правило, да, как работает управление памятью в UNIX. Если вы используете Linux с недавним glibc и используете этот malloc, вы можете вернуть свободную память в ОС. Я не уверен, что Perl делает это.

Если вы хотите работать с большими наборами данных, не загружайте все это в память, используйте что-то вроде BerkeleyDB:

https://metacpan.org/pod/BerkeleyDB

Пример кода, украденного дословно:

  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 ;

(ОК, а не дословно. Их использование use vars - это... наследие...)

Таким образом вы можете хранить гигабайты данных в хэше, и вы будете использовать только небольшой бит памяти. (В принципе, любой пейджер BDB решает сохранить в памяти, это контролируемо.)

Ответ 2

В общем случае вы не можете ожидать, что perl выведет память в ОС.

Смотрите FAQ: Как я могу освободить массив или хэш, чтобы моя программа сжималась?.

Обычно вы не можете. Память, выделенная для лексических элементов (т.е. my() переменных), не может быть восстановлена ​​или повторно использована, даже если они выходят за рамки. Он зарезервирован, если переменные возвращаются в область видимости. Память, выделяемая глобальным переменным, может быть повторно использована (в вашей программе) с помощью undef() и/или delete().

В большинстве операционных систем память, выделенная для программы, никогда не может быть возвращена системе. Вот почему долговременные программы иногда перестраиваются. Некоторые операционные системы (в частности, системы, использующие mmap(2) для выделения больших блоков памяти) могут восстановить память, которая больше не используется, но в таких системах perl должен быть сконфигурирован и скомпилирован для использования ОС malloc, а не perl 's.

Всегда полезно прочитать список часто задаваемых вопросов, также установленный на вашем компьютере, прежде чем тратить свое время.

Например, Как я могу заставить свою программу Perl меньше памяти?, вероятно, относится к вашей проблеме.

Ответ 3

Почему вы хотите, чтобы Perl выпустил память для ОС? Вы могли бы просто использовать более крупный своп.

Если вам действительно нужно, выполните свою работу в разветвленном процессе, а затем выйдите.

Ответ 4

Попробуйте перекомпилировать perl с помощью опции -Uusemymalloc, чтобы использовать систему malloc и бесплатно. Вы можете увидеть несколько разных результатов.