В 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 Текущее использование памяти: Virt: 6,9K RES: 2,7K Длина хеша: 0 Hash Mem Общий размер: 92 Длина скаляра: 0 Scalar Mem Общий размер: 12 Нажмите Enter (добавить в память): Добавление данных в общий Varable 100000 раз Готово Добавление данных Текущее использование памяти: Virt: 228K RES: 224K Длина хэша: 100000 хэш-мем. Общий размер: 116813243 Длина скаляра: 111100000 Скалярная память Общий размер: 111100028 Нажмите Enter (установите Varable на ничего): Текущее использование памяти: Virt: 228K RES: 224K Длина хэша: 100000 хэш-мем. Общий размер: 116813243 Длина скаляра: 0 Scalar Mem Общий размер: 111100028 Нажмите Enter (очистить данные): Очистить данные Текущее использование памяти: Virt: 139K RES: 135K Длина хеша: 0 Hash Mem Общий размер: 92 Длина скаляра: 0 Scalar Mem Общий размер: 24 Нажмите Enter (начать заново):
Итак, как вы можете видеть, память уменьшается, но уменьшается только на размер скаляра. Есть идеи как освободить память от хэша?
Также Devel::Size
показывает, что хеш занимает только 92 байта, хотя программа все еще использует 139K.
4 ответа
Как правило, да, именно так работает управление памятью в 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 решает сохранить в памяти; это контролируемо.)
В общем, вы не можете ожидать, что Perl освободит память для ОС.
См. FAQ: Как освободить массив или хеш, чтобы моя программа сократилась?,
Вы обычно не можете. Память, выделенная для лексики (т.е.
my()
переменные) не могут быть восстановлены или использованы повторно, даже если они выходят за рамки. Он зарезервирован на случай, если переменные вернутся в область видимости. Память, выделенная для глобальных переменных, может быть повторно использована (в вашей программе) с помощьюundef()
и / илиdelete()
,В большинстве операционных систем память, выделенная для программы, никогда не может быть возвращена в систему. Вот почему долго работающие программы иногда сами себя исполняют. Некоторые операционные системы (в частности, системы, которые используют
mmap(2)
для выделения больших кусков памяти) может восстановить память, которая больше не используется, но в таких системах perl должен быть настроен и скомпилирован для использования ОСmalloc
неperl
"S.
Перед тем, как тратить время, всегда полезно прочитать список часто задаваемых вопросов, также установленный на вашем компьютере.
Например, как я могу заставить мою программу на Perl занимать меньше памяти? вероятно, имеет отношение к вашей проблеме.
Почему вы хотите, чтобы Perl освободил память для ОС? Вы можете просто использовать больший своп.
Если вы действительно должны сделать свою работу в раздвоенном процессе, а затем выйти.
Попробуйте перекомпилировать perl с параметром -Uusemymalloc, чтобы использовать систему malloc и free. Вы можете увидеть некоторые другие результаты