Thu 25 Jan 2007
Ошибка в Perl’овом Thread::Semaphore: Утечка памяти (решение прилагается)
Posted by Scoundrel under Development ·
Я потратил сегодня почти весь день пытаясь найти и поправить очень странную ошибку в одном из наших серверных приложений, написанных на Perl. И, как выяснилось в процессе, в системных библиотеках Perl или, может быть, в его интерпретаторе, есть крайне неприятная ошибка.
Проблема в следующем. Если вы попытаетесь использовать модуль “threads” вместе с модулем “Thread::Semaphore”, как это описано в официальной документации по языку Perl (perlthrtut), вы получите утечку памяти размером около 4kb на каждый вызов $semaphore->up. Следовательно, следующий простой пример кода вызовет просто огромные утечки памяти (около 100 Mбайт в секунду на моем тестовом сервере):
use threads;
use Thread::Semaphore;
my $xxx = new Thread::Semaphore();
my $x = new threads(\&mythread);
$x->join;
sub mythread {
while (1) {
$xxx->down();
$xxx->up();
}
}
После 5 часов секса веселья с нашим проектом и создания приведенного выше тесткейса я решил посетить “официальныйl” IRC-канал Perl’а (#perl) на irc.perl.org. Народ там оказался, мягко говоря, грубоват и помочь не захотел… Спасибо тому единственному участнику чата, который честно послал меня в сторону канала #p5p, где обитает народ, занимающийся багами (я так понял). Этот канал был практически мертв (хотя, может быть дело было в том, что в америке была ночь), но я нашел там одного отличного парня. Его имя Sam Vilain. Он потратил уйму времени и выяснил, что вызов Perl’ового bless на shared-переменных приводит к необъяснимому memory leak’у (у меня - 4Кб на вызов).
Благодаря подсказкам и советам Sam’а я написал простой модуль для Perl’а, который может быть прозрачно использован как замена стандартному Thread::Semaphore. То есть просто делаете use Sema4; и все становится хорошо:
use threads::shared;
sub new {
my $class = shift;
my $val : shared = @_ ? shift : 1;
# Workaround because of memory leak
return bless \\$val, $class;
}
sub down {
my $s = shift;
# Double dereferencing
$s = $$s;
lock($$s);
my $inc = @_ ? shift : 1;
cond_wait $$s until $$s >= $inc;
$$s -= $inc;
}
sub up {
my $s = shift;
# Double dereferencing
$s = $$s;
lock($$s);
my $inc = @_ ? shift : 1;
($$s += $inc) > 0 and cond_broadcast $$s;
}
1;
Собственно, выводом из всего произошедшего стала мысль… А не стоит ли нам выбросить на помойку старые “мертвые” языки, комьюнити которых не способно реализовать стандартные треды в 21-м веке? А, самое главное, комьюнити которых тупо плюет в лицо человеку пришедшему с проблемой в их core libraries? Я думаю, что мне и правда стоит попробовать что-нибудь другое… Вот только не знаю, что именно… может быть Ruby (ну не нравится мне синтаксис Python’а)? Посмотрим…
- MySQL Master-Master Replication Manager 1.0 Released
- MMM checkers memory leak?
- How to run GUI-programs on a server without any monitor
- Как Получить Данные Для Mrtg Не Запуская SNMP-Сервер?
- Oracle Database 10g Express Edition: Не только для обучения
January 25th, 2007 at 7:20 am
> ну не нравится мне синтаксис Python’а
Если это конкретно про его отступы - то меня они очень сильно раздражали, пока просто не пришлось поправить скрипт на питоне. Ну и с тех пор я забросил перл.
January 25th, 2007 at 8:13 pm
> выбросить на помойку старые “мертвые” языки
При всем уважении к вам, по-моему, вы погорячились.
Руби очень хорош.
January 25th, 2007 at 8:18 pm
2Петр:
Не знаю… Я до сих пор не понимаю, как можно в 2007-м году вот так вот тупо оставаться на уровне 85-го года с “поддержкой” тредов через жо^H^H форки…
January 25th, 2007 at 9:22 pm
я тоже когда то не любил питон;) отступы казались мне дикостью. Потом попробовал - и надо же, оказался чудесный язык! а отступы - просто супер!
January 25th, 2007 at 9:37 pm
> поддержкой тредов через форки
Цепляюсь к словам
Пайтон прекрасен!
January 25th, 2007 at 9:47 pm
Возможно, отрывок в тему.
«Многотредный … метод популярен в Windows-средах, потому что создание новых процессов сравнительно дорого, а вот треды в Windows сделаны очень неплохо.
Впрочем, для приложений на Питоне это не рекомендуется в любом случае из-за Global Interpreter Lock (http://docs.python.org/api/threads.html).»
Но это нисколько не портит пайтон.
Статья написана Иваном Сагалаевым. Полная версия — http://softwaremaniacs.org/blog/2007/01/08/controlled-download-2/
January 25th, 2007 at 9:57 pm
2Петр:
Ну они реально в перле через форки, так еще и семафоры кривые
А насчет питона - не могу себя сломать. отступы эти….
January 25th, 2007 at 10:01 pm
Агащазблин! Вот вы меня простите, но мне треды удобнее как минимум потому, что никакого IPC городить не надо. Тупо взял переменную, сделал семафор рядышком, чтобы синхронизироваться и все довольны
Вот такие вот дела. А так и в перле я мог бы форкнуться и сделать IPC какое-нить (такое даже есть, но в другой части этого же проекта)… но не хочется городить огород, когда реально хватает тредов и примитивных средств синхронизации
January 26th, 2007 at 6:55 am
К Ruby стоит присмотреться. Однако нормальных системных тредов там нет. Во всяком случае, пока нет. Кроме того, по количеству доп. модулей Perl сильно обставляет и Python, и Ruby. Опять же, пока обставляет.
И еще - не стоит обижаться на все сообщество, нарвавшись на несколько гоблинов. Можно случайно заскочить на LOR с вопросом по Linux’y :))) а потом, попивая валерьянку, перебираться на Solaris.
January 26th, 2007 at 2:43 pm
> А насчет питона - не могу себя сломать. отступы эти….
Стоит только один раз попробовать, и ты втянешься.
January 26th, 2007 at 9:25 pm
> они реально в перле через форки
Где можно прочитать об этом?
Мои предположения основаны на доке: http://search.cpan.org/~jdhedden/threads-1.58/threads.pm
January 26th, 2007 at 9:32 pm
2Петр:
Мне об это рассказал тот самый core-девелопер, с которым мы разбирались с проблемой… Может я его правда понял как-то не так… Но anyways, семафоры у них дохлые
January 28th, 2007 at 8:32 am
Видимо, он не только хам.
Потоки в других языках тоже сильно увы.
March 7th, 2007 at 12:41 pm
Извините, а у какого веб-языка на юниксе хорошо реализованы треды?
Практически к любому приложению, даже на сях, идет коммент: треды вы можете попробовать поюзать, но лучше не надо.
Да, это особенность среды, в которой форк исторически был быстрее создания треда.
Прикопайтесь еще к примеру, что в винде нет форка. что за бред работать в такой системе в 2007 году.
March 9th, 2007 at 6:27 am
2Mons: Согласитесь, что “хорошо” и “чтобы работало” - это разные вещи. Я хотел от перла именно “чтобы работало” - у меня не сильно критичное к роизводительности и т.п. вещам приложение… но оно работает месяцами без перезапуска и меморилики в базовых операциях с тредами (семафорами) просто недопустимы.
А насчет винды и форка - так его нет и все тут… вот если бы он был, но работал криво - это было бы корректное сравнение… хотя все равно - не стоит в ней работать
March 18th, 2007 at 5:38 pm
>Я до сих пор не понимаю, как можно в 2007-м >году вот так вот тупо оставаться на уровне >85-го года с “поддержкой” тредов через жо^H^H >форки…
Вот это вы сильно написали
Треды не реализованы через форк. Если бы так было, то зачем тогда нужны были треды, новый алиас?
В доке по threads::shared (Thread::Semaphore подключает) в разделе BUGS написано: “bless is not supported on shared references. In the current version, bless will only bless the thread local reference and the blessing will not propagate to the other threads. This is expected to be implemented in a future version of Perl”.
Такое бывает, когда натыкаешься на баг модуля. Здесь два решения:
- либо ждать новой версии,
- либо обойти этот баг.
Вы обошли, но зря поменяли названия модуля, нужно было оставить то же название, положить в директорию, где находится скрипт и в самом скрипте:
BEGIN { unshift @INC, pop @INC } # perl hack
use Threads::Semaphore;
Когда выйдет обновление, можно все скрипты grep’нуть на наличие такого комментария и убрать “затычки”.
Такое решение очень эффективно, т.к. каждый день Perl становится все лучше и лучше.
Кстати, можно было не использовать Thread::Semaphore, а просто указать lock там, где надо
На счет “комьюнити которых тупо плюет в лицо человеку пришедшему с проблемой в их core libraries” - обычно люди, хорошо разбирающиеся в каком-то деле, не сидят в чатах, у них на это времени нет.
>А не стоит ли нам выбросить на помойку старые “мертвые” языки
Perl - точно НЕ стоит!
March 22nd, 2007 at 9:53 am
Ruby’s syntax is better than Python’s syntax.
That was the main seller for me.
Yes, having to use “ends” can be redundant, but you dont have to NEED USE whitespace for code that works (compare irb to python interpreter for example)
You dont have to carry implicit (self) which is so annoying to read.
You can omit () if it fits your style or you are lazy.
Last but not least, using classes and objects in
ruby doesnt feel like a fix-up solution like in Python.
October 29th, 2007 at 5:53 pm
[...] semaphores implementation caused huge memory leaks [...]
December 5th, 2007 at 12:58 pm
Мега thanx вам с Sam Vilain !!
Я столкнулся с той же проблемой, и моментально нашел этот пост через
http://www.google.ru/search?complete=1&hl=ru&newwindow=1&q=perl+threads+semaphore+memory+leak&btnG=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA&lr=