Каким образом я могу вернуть память из моего сценария Perl и/или предотвратить perl из пула управления памятью?Как я могу восстановить память из perl?
ответ
Наиболее эффективным методом является наличие большого количества виртуальной памяти, так что память, выделяемая perl, но не часто используемая, просто выгружается.
Кроме того, чрезвычайно сложно сохранить perl из-за того, что он выделяет больше памяти с течением времени ... не потому, что он просочился, а потому, что perl действительно любит выделять вещи в случае их повторного использования. Небольшая кодовая база с довольно последовательными размерами строк будет немного отставать, но это исключительный случай.
Под апачем, историческая техника заключалась в том, чтобы убить процесс, когда он достигает определенного размера или после определенного количества запросов. Это не так хорошо работает с резьбовыми MPM ...
Undef часто, в глубину.
Глубина первой не должна иметь никакого значения, если у вас нет других ссылок на глубокие вещицы. – ysth
Как ответили на параллельный вопрос: In general, you cannot expect perl to release memory to the OS перед завершением/завершением сценария. По окончании вся выделенная память возвращается ОС, но это функция ОС и не зависит от Perl.
Так у вас есть ограниченное количество вариантов, если у вас есть длинный запущенный сценарий:
- делегирование памяти ресурсоемкой частей для дочерних процессов. Таким образом, память будет освобождена, когда каждая часть будет закончена. Цена для оплаты - IPC-связь.
- Вы используете свои собственные структуры, управляемые памятью, как правило, на основе Tie. Цена, которую нужно заплатить, заключается в том, чтобы обрабатывать загрузку/хранение в/из backstore, если структура не является простой (даже стандартный Hash - простой, но довольно мощный).
- Вы используете память как ценный ресурс, и optimize its usage (используя меньшие конструкции, позволяя повторное использование памяти и т. Д.).
Perl «поддерживает» возврат памяти в операционную систему, если операционная система готова вернуть эту память. Я использую цитаты, потому что, IIRC, Perl не обещает, когда он вернет эту память.
Perl в настоящее время обещает, когда деструкторы будут работать, когда объекты будут освобождены (и, особенно, в каком порядке это произойдет). Но освобожденная память переходит в пул для Perl, который будет использоваться позже, и эта память - в конце концов - будет выпущена в операционную систему, если операционная система ее поддерживает.
Это похоже на мой опыт - когда никакое количество неопределений или уничтожение объектов контейнера не уменьшает объем памяти программы. – ddoxey
У меня была аналогичная проблема, когда я читаю большое сообщение SOAP с сервера. Насколько я могу судить, SOAP::Lite
не может передавать данные, поэтому он должен загрузить все это в память, прежде чем я смогу обработать его.
Даже в результате мне нужен только небольшой список, это приводит к тому, что объем памяти в программе будет находиться в гигабайтах. Это проблема, потому что сценарий выполняет большую сетевую связь, в результате чего память остается выделенной в течение длительного времени.
Как уже упоминалось ранее, единственными истинными решениями являются: a) перепроектировать все или b) fork/exec.Я здесь пример вилке/Exec, который должен работать, чтобы проиллюстрировать решение:
#
# in general, perl will not return allocated memory back to the OS.
#
# to get around this, we must fork/exec
sub _m($){
my $ln = shift;
my $s = qx/ ps -o rss,vsz $$ | grep -v RSS /;
chomp($s);
print STDERR "$$: $s $ln>\n";
}
sub alloc_dealloc(){
# perldoc perlipc for more interesting
# ways of doing this fork:
defined(my $pid = open(KID,'-|')) || die "can't fork $!";
my $result = -1;
if($pid){
my $s = <KID>; eval $s;
}else{
_m(__LINE__);
my $a = [];
# something that allocates a lot of memory...
for($i=0;$i<1024*1024*16;$i++){
push(@$a,int(rand(3)));
}
_m(__LINE__);
# something that processes that huge chunk
# of memory and returns a very small result
my $r=0;
for(@$a){ $r+=$_; }
_m(__LINE__);
@$a =();
_m(__LINE__);
undef($a);
_m(__LINE__);
# STDOUT goes to parent process
print('$result = '.$r.";\n");
exit;
}
return $result;
}
while(1){
_m(__LINE__);
my $r = alloc_dealloc();
print "Result: $r\n";
_m(__LINE__);
}
Это будет работать вечно, производя такой вывод:
9515: 1892 17876 54>
9519: 824 17876 24>
9519: 790004 807040 31> # <-- chunk of memory allocated in child
9519: 790016 807040 38>
9519: 790068 807040 41>
9519: 527924 544892 43> # <-- partially free()d, but mostly not
9515: 1976 17876 57> # <-- parent process retains its small footprint
Result: 16783001
Я соблазн сказать «убить» и/или «не запускайте его в первую очередь» :) Что вы подразумеваете под «пулом управления памятью»? Здесь также может влиять ваша ОС хоста. –