2009-11-03 3 views
2

Каким образом я могу вернуть память из моего сценария Perl и/или предотвратить perl из пула управления памятью?Как я могу восстановить память из perl?

+4

Я соблазн сказать «убить» и/или «не запускайте его в первую очередь» :) Что вы подразумеваете под «пулом управления памятью»? Здесь также может влиять ваша ОС хоста. –

ответ

8

Наиболее эффективным методом является наличие большого количества виртуальной памяти, так что память, выделяемая perl, но не часто используемая, просто выгружается.

Кроме того, чрезвычайно сложно сохранить perl из-за того, что он выделяет больше памяти с течением времени ... не потому, что он просочился, а потому, что perl действительно любит выделять вещи в случае их повторного использования. Небольшая кодовая база с довольно последовательными размерами строк будет немного отставать, но это исключительный случай.

Под апачем, историческая техника заключалась в том, чтобы убить процесс, когда он достигает определенного размера или после определенного количества запросов. Это не так хорошо работает с резьбовыми MPM ...

2

Undef часто, в глубину.

+0

Глубина первой не должна иметь никакого значения, если у вас нет других ссылок на глубокие вещицы. – ysth

9

Как ответили на параллельный вопрос: In general, you cannot expect perl to release memory to the OS перед завершением/завершением сценария. По окончании вся выделенная память возвращается ОС, но это функция ОС и не зависит от Perl.

Так у вас есть ограниченное количество вариантов, если у вас есть длинный запущенный сценарий:

  • делегирование памяти ресурсоемкой частей для дочерних процессов. Таким образом, память будет освобождена, когда каждая часть будет закончена. Цена для оплаты - IPC-связь.
  • Вы используете свои собственные структуры, управляемые памятью, как правило, на основе Tie. Цена, которую нужно заплатить, заключается в том, чтобы обрабатывать загрузку/хранение в/из backstore, если структура не является простой (даже стандартный Hash - простой, но довольно мощный).
  • Вы используете память как ценный ресурс, и optimize its usage (используя меньшие конструкции, позволяя повторное использование памяти и т. Д.).
2

Perl «поддерживает» возврат памяти в операционную систему, если операционная система готова вернуть эту память. Я использую цитаты, потому что, IIRC, Perl не обещает, когда он вернет эту память.

Perl в настоящее время обещает, когда деструкторы будут работать, когда объекты будут освобождены (и, особенно, в каком порядке это произойдет). Но освобожденная память переходит в пул для Perl, который будет использоваться позже, и эта память - в конце концов - будет выпущена в операционную систему, если операционная система ее поддерживает.

+1

Это похоже на мой опыт - когда никакое количество неопределений или уничтожение объектов контейнера не уменьшает объем памяти программы. – ddoxey

0

У меня была аналогичная проблема, когда я читаю большое сообщение 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