Sunday, August 16, 2009

Gtk-Message: Failed to load module "globalmenu-gnome"

Некогда пробовал gnome-globalmenu, не понравилось, убил.

С тех пор ловил при каждом запуске gtk приложения такую бяку:

Gtk-Message: Failed to load module "globalmenu-gnome": libglobalmenu-gnome.so: cannot open shared object file: No such file or directory
и


Решение тут:

http://magnus-k-karlsson.blogspot.com/2009/02/remove-gnome-globalmenu.html

Вкратце в gconf-editor /apps/gnome-settings-daemon/gtk-modules задизейблить ( убрать галочку) globalmenu-gnome

Wednesday, August 12, 2009

php и циклические ссылки

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

После беглого просмотра кода и сопутствущих классов, время было оптимизировано до минуты. Проблема была в том, что первоначальная версия была написана не очень хорошим программистом, а остальные ленились кардинально переписать приложение. Также для генерации отчета в циклах использовались классы, которые на многие действия совершали запросы к базе, а вызывались эти методы внутри цикла. Использовав упреждающее чтение всех необходимых данных в память и минимальную модификацию классов для использования получанных данных в случае их наличия, приложение стало работать гораздо быстрее (1 минута из которой 40 секунд происходит чтение всех необхомых данных в память, 20 секунд непосредственно обработка и запись данных). Ну а количество запросов сократилось до 3-х вместо 3*количество записей в обрабатываемых таблицах.

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

Вторая проблема которую я увидел это то, что это приложение было по сути копипастом из одного часто используемого метода, в итоге переписав и то, и другое, я получил скрипт, который исправно работал, но в 10 раз медленнее минутной версии, но обладал замечательным свойством, что был готов для повторного использования, стал более гибким, и читать его стало проще. Однако возникла следующая проблема, уже на 200.000 записях он стал отжирать 4 гб памяти и операционной системе это очень не нравилось, впрочем как и мне. Почистив код, я убедился что происходит утечка памяти.

Вот код, который вольно воспроизводит сложившуюся ситуацию.

 

class DataSource // в моем случае это был итератор по таблице базы данных
{
protected $_counter = 1;
public function next()
{
return array('xxxxxxxxxxxxxxxxxxxxxxxx' => 'yyyyyyyyyyyyyyyyyyy');
}
}

class UserHelper // род классов, для получения данных связаных с пользователями, но выходящих за рамки этого объекта
{
protected $_u = null;
public function __construct(User $u)
{
$this->_user = $u;
}
public function getSomeData()
{
return array('x' => 10, 'y' => 20);
}

public function __desctruct()
{
$this->_u = null;
}
}

class User
{
protected $_dbRow = array();
protected $_helpers = array();
public function __construct(array $data )
{
$this->_dbRow = $data;
}

public function getHelper()// получения хелпера, в данном случае ситуация урезана до одного
{
if ( isset($this->_helpers['x'] ) )
return $this->_helpers['x'];
return $this->_helpers['x'] = new UserHelper($this); // автор посчитал это полезным
}

public function __destruct()
{
unset($this->_dbRow);
$this->_helpers['x'] = null;
}
}

// кусок кода вызвавший проблему.
$ds = new DataSource();
for($i= 1; $i++; $i< 1000000)
{
$u = new User($ds->next()); // загружаем пользвоателя напрямую по данным
$helper = $u->getHelper();
$helperData = $helper->getSomeData();// получаем данные хелпера
//делаем то что нужно с данными
unset($helperData);
unset($helper);
unset($u); // думаем что убили пользователя
}


При запуске этого скрипта и запущенном топе, видим как память отжирается без остановки.

Проблема в циклических ссылках. Не охота это описывать можно почитать ТУТ

После того как я нашел утечку. Код переписан в таком виде


$ds = new DataSource(); // получаем итератор
for($i= 1; $i++; $i< 1000000)
{
$u = new User($ds->next()); // загружаем пользвоателя напрямую по данным
//$helper = $u->getHelper(); вот тут и была проблема.
$helper = new UserHelper($u);
$helperData = $helper->getSomeData();// получаем данные хелпера
//делаем то что нужно с данными
unset($helper);
unset($u); // думаем что убили пользователя.
}



После этого, время выполнения приложения стало чуть больше 20 % от первоначальной минуты, ну а раход памяти стал фиксированным ~300-400 MB

Вывод: Консольные приложения обычно пишутся для больших объемов данных, и то что прощается при выполнении маложивущей веб-страницы, выходит боком при долгой работе приложения.
 
Каталог сайтов, Добавить сайт