Есть ли способ, которым я могу заставить mod_perl повторно использовать буферную память? - PullRequest
2 голосов
/ 16 марта 2010

У меня есть скрипт Perl, работающий в mod_perl, который должен записывать большой объем данных клиенту, возможно, в течение длительного периода. Поведение, которое я наблюдаю, состоит в том, что, как только я что-то печатаю и сбрасываю, буферная память не освобождается, хотя я rflush (я знаю, что ОС не может восстановить ее).

Так работает mod_perl и есть ли способ заставить его периодически освобождать буферную память, чтобы я мог использовать это для новых буферов вместо того, чтобы брать больше из ОС?

Просто чтобы уточнить, я сам не использую никаких буферов, и в моем коде нет утечек. Рассмотрим следующий простой пример:

  sub handler { 
     my $request = shift; 
     my $boundary = time; 
     $request->content_type("multipart/x-mixed-replace;boundary=\"$boundary\";"); 
     for (;;) { 
        $request->print("--$boundary\n"); 
        $request->print("Content-type: text/html; charset=utf-8;\n\n"); 
        $request->print("$data\n\n"); 
        $request->rflush;
     } 
     return Apache2::Const::OK; 
  } 

Это сильно просачивается, и мой запрос сохраняется, поэтому он может быть активным в течение нескольких дней.

Ответы [ 3 ]

2 голосов
/ 16 марта 2010

Не возвращение памяти в ОС является стандартным поведением самого интерпретатора perl, не специфичным для mod_perl как такового. Кроме использования совместно используемой памяти (которую, IIRC, вы обрабатываете выделение / перераспределение вручную) или завершения процесса, я не знаю ни одного способа заставить perl освободить память обратно в хост-ОС. *

Выход переменных из области видимости позволит perl повторно использовать эту память для других переменных, но не вернет ее в ОС.

Редактировать: Я просто перечитал вопрос и понял, что вы просто ищете способ позволить perl повторно использовать память, не пытаясь освободить ее для ОС. В этом случае, использование лексических (my) переменных и ограничение их наименьшей возможной областью вместо раннего определения глобального буфера и сохранения его вокруг навсегда.

0 голосов
/ 02 июня 2010

Ваш цикл for (;;) никогда не может закончиться так, как написано, что приведет к более серьезным проблемам, чем утечка памяти. Метод печати должен выделять некоторую память, вероятно, как часть записи запроса, которая обычно освобождается при очистке запроса. Это происходит в коде C, либо в mod_perl2, либо в Apache2.

Вам придется изменить свой подход, чтобы обойти это. Вместо того чтобы отправлять длительный ответ из обработчика mod_perl, перенаправьте пользователя через настройку ProxyPass в программу, которая напечатает ответ в STDOUT. (По сути, это CGI-скрипт.) Сценарий может быть чисто Perl, где будут работать методы, упомянутые другими авторами об ограничении области действия переменных. Ответ по-прежнему будет проходить через Apache, но при работе в качестве обратного прокси-сервера Apache имеет фиксированный набор буферов, через которые он копирует данные в ведро-бригаде; Я никогда не видел, чтобы процессы обратного прокси-сервера занимали много памяти, несмотря на то, что проходили через огромные объемы данных.

0 голосов
/ 16 марта 2010

Отпустите все ваши ссылки на буфер. Например, если вы использовали строку в качестве буфера, как в

$buf = "really long string " . "and other methods that make it huger";
print SOMEWHERE $buf;
$buf = ""; # or undef $buf according to taste

Должен вернуть хранилище, ранее указанное $ buf, в свободный пул.

...