Антон С.
1316 сообщений
#14 лет назад
И снова здравствуйте.
Думаю многим будет интересна эта тема.
Ситуация - есть парсер на PHP. Написан не мной, но я его сейчас дорабатываю.
После доработки парсер получил возможность парсить все товары, а не 20%, как было ранее.
Сразу же всплыла проблема утечки памяти. Скрипту выделяется 256 MB, но проблему это не решает. Просто скрипт работает чуть подольше.

Как решаю:
1) unset переменных.
2) mysql_free_result.
3) imagedestroy;

Вопросы:
1) Если скрипты делает print в консоль для дебага - он тратит память?
2) Если делается mysql_query, результат которого не пишется в переменную - он тратит память? (нужно ли его free_result?)
3) Если функция заканчивает работу - переменные все автоматом сбрасываются или их надо unset делать?
4) Есть ли какая-то возможность полностью очистить все результаты mysql здесь и сейчас, чтобы не mysql_free_result каждый?
5) Любые идеи, инфа по этой теме? Какие еще есть методы борьбы?
Роман П.
1599 сообщений
#14 лет назад
Ну, сделал print или mysql_query и посмотри memory_get_usage - сам узнаешь, раз так непонятно)

Для начала надо узнать, где утекает, а не гадать на форуме. Потом удивишься, наконец зайдя в гугл и узнав, что можно сделать unset переменной, а память все-равно не освободится из-за некоторых забавных особенностей работы php.
Антон С.
1316 сообщений
#14 лет назад
Crist, благодарю, за демонстрацию ЧСВ, но мне интересен более конструктивный диалог.

>Для начала надо узнать, где утекает, а не гадать на форуме.
Это слишком проблематично. Парсер реально огромен ) XDebug нету )

Я решил unset + mysql_free_result все, что только можно.

>что можно сделать unset переменной
уже такое видел. Это в 100% или есть какой-то шанс ?)) а что если

while (is_set($var))
{
unset($var);
}


Дополнение: еще нашел косяк - нету imagedestroy ) сейчас добавлю.
Кирилл Е.
2817 сообщений
#14 лет назад
Imagedestroy - оно то работае..
..но иногда открывая большие картинки, например 3000х4000 (некоторые умники и такие картинки закидают, хз где они их берут, разве что с фотика напрямую)..
..памяти не хватает во время imagecreate(jpeg/png), для некоторых картинок 3000х4000 мемори лимит = 128мб было мало - картинок таких было 10-15 - решилось просто: скачал всё локально и программно за 5 сек уменьшил размер фоток в 2 раза и залил обратно - всё заработало.

Долго сидел парился - какого чёрта памяти было мало - оказалось одна большая картинка где-то в конеце всего массива данных портит весь кайф

Потому рекомендую перед тем как открыть картинку - смотреть её размер и считать хватит ли памяти - если нет - отложить картинку для ручной обработки, разве что написать

Чтобы на данные не хватило 256мб - нужно наплевательски делать)..

А вообще можно пошаговой импорт делать: извлекли 2-3к записей, сгенерили страницу, на ней инфа в <input type='hidden' /> о последней строке и откуда нужно начать, и через 10-15 сек кликаем кнопку для продолжения импорта..

В этом случае, если хоть чуть следили за мусором, потребности в большом мемори лимит или времени на выполнение нет. оно себе хоть целый день может так по чуть-чуть парсить.
Антон С.
1316 сообщений
#14 лет назад
kirilev, вроде таких больших изображений нет. товаров многие тысячи, так что может где-то накапливается. мало ли. на эту тему я не могу ничего умного найти в плане "узких мест".

Цитата:
А вообще можно пошаговой импорт делать: извлекли 2-3к записей, сгенерили страницу, на ней инфа в <input type='hidden' /> о последней строке и откуда нужно начать, и через 10-15 сек кликаем кнопку для продолжения импорта..

Бюджет этого дела ограничен, хотя это одно из решений .если ничего не поможет. так и сделаю.
Николай М.
1895 сообщений
#14 лет назад
ПХП очень розточивый в плане памяти и ресурсов, откуда утечка в скриптовом языке я тут совсем не понимаю один только вариант - если это всетаки утечка, то апдейтить модули, сервак.

Еще раз повторюсь в скриптовом языке несуществует понятия утечек памяти, их создают напр. апачи, ПХП интерпритатор, молули и т.д.

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

В общем очень много причин могут призводить к росту памяти и xDebug врятли тут поможет. Если вы освобождаете переменную, то это совсем еще не значит что память освбодилась, может просто указатель освободился на данные. Была бы это программа напр. на С++ или на Делфи, то все можно было бы четко отследить, здесь же пальцем в небо...
Володимир П.
164 сообщения
#14 лет назад
Оффтопик
Цитата ("Enkvist"):
Crist, благодарю, за демонстрацию ЧСВ, но мне интересен более конструктивный диалог.

Еще не слышал от Crist конструктивный диалог XD
Антон С.
1316 сообщений
#14 лет назад
Вопрос решился. Я уже сам во всем разобрался.

>Еще раз повторюсь в скриптовом языке несуществует понятия утечек памяти
Я мог не очень корректно использовать этот термин )

Фишка в том, что скрипт постоянно рос в RAM ... после чтения буржуйских статей все стало ясно и выход был найден.

P.S. Я не совсем понял, но судя по всему, есть надежда, что в будущих версиях PHP unset такие начнет работать так, как следует ) (то-есть приделаю сборщик мусора наконец-то).
Андрей Халецкий
3562 сообщения
#14 лет назад
Всегда радовали топики формата:

У меня есть проблема, вот ее описание, помогите решить.
Далее перепалка отдаленная от темы.
Потом - все, разобрался решил всем спасибо.

Неужели ни на секунду не задумывались что стоит выложить решение?
Антон С.
1316 сообщений
#14 лет назад
SmartDesign, а зачем? ) я выложил тему - реально только Kirilev ответил.. и то самое простое.
Все остальные игнорят (наверное не хотят "палить темы", кто-то в очередной раз отрабатывает свои комплексы, кто-то просто демонстрирует интеллект, но по теме - ничего вообще. (то, что unset не работает - да это и так понятно).
Вы вот почему только сейчас появились , а не когда я спрашивал? )
Я не верю в то, что на веблансере никто не знает, как очищать память в PHP.
Николай М.
1895 сообщений
#14 лет назад
Я вообщето писал о указателях, а это как раз в десятку судя из вашего ответа)))Цитата ("MMM_Corp"):
Если вы освобождаете переменную, то это совсем еще не значит что память освбодилась, может просто указатель освободился на данные
Роман П.
1599 сообщений
#14 лет назад
Enkvist, я давал ссылку на (про циклические ссылки и указатели как раз), но модератор почему-то потер, я даже не воткнул почему.

Цитата ("Enkvist"):
а зачем? )


Т.е. вы вовсе не осуждаете такую манеру поведения и тоже следуете ей?
Антон С.
1316 сообщений
#14 лет назад
Crist, твоя ссылка на вопрос не отвечает. ты почитай, что там написано. там не сказано, как очищать память. статья абсолютно бесполезная.
MMM_Corp, вы не предложили не единого метода решения. от того, что unset плохой - мне легче не становится.

>Т.е. вы вовсе не осуждаете такую манеру поведения и тоже следуете ей?
Когда я вижу, что кто-то что-то спрашивает и я знаю ответ - я обязательно всегда помогу. Этим я демонстрирую свою гражданскую позицию.
Кирилл Е.
2817 сообщений
#14 лет назад
Только не пойму почему гонят на unset?

Удаляет переменную с памяти или нет? Решил лично проверить, может разработчики РНР не настолько глупые?

Делал очень просто: в массив заполняем на 100 переменных, используя memory_get_usage() смотрим что память действительно заполняется и массив "растёт", но если заполнить массив и сделать unset() - память не растёт, элемент массива действительно убирается в памяти.

Вот код контр.примера:

<pre>
<?

function get_mu(){
return round(memory_get_usage() / 1024, 2) . "kb\n";
}

$n = 100;
get_mu();

$array = array();

$test_result = "";

for($i = 0; $i < $n; $i++){
$array = true;
//unset($array); // <------------ Первый раз запускаем скрипт в закомментированной строкой, второй раз запустим и сделаем unset().
echo get_mu();
}


?>

<pre>


Запуская дважды получил результат:

Без unset()

309.36kb
309.44kb
309.52kb
309.59kb
309.67kb
309.75kb
309.83kb
309.91kb
310.02kb
310.09kb
...
317.41kb
317.48kb
317.56kb


Используя unset()

309.38kb
309.38kb
309.38kb
309.38kb
309.38kb
309.38kb
...
309.38kb
309.38kb
309.38kb


потому обсирание unset считаю необоснованным.
Антон С.
1316 сообщений
#14 лет назад
kirilev, unset для массивов работает. а теперь проверьте тоже самое просто для переменной или для класса.
Кирилл Е.
2817 сообщений
#14 лет назад
Enkvist, удивительно.. проверял тоже с переменными и экземплярами класса - всё отлично работает.

Если у кого не работает unset() - пусть наведёт контр.пример что он действительно не работает, может быть проблема не в unset()?
Антон С.
1316 сообщений
#14 лет назад
<?
include('include/simple_html_dom.php');

function get_mu(){
return round(memory_get_usage() / 1024, 2) . "kb\n";
}

class a{
private $a;
private $b;

function a()
{
$this->a = file_get_contents(';);
$this->b = str_get_html($this->a);
}

}



print get_mu()."\n";
$a = new a();
print get_mu()."\n";
unset($a);
print get_mu()."\n";


391.63kb

10158.53kb

9972.77kb
Кирилл Е.
2817 сообщений
#14 лет назад
Запускал без
Цитата:
include('include/simple_html_dom.php';

и "$this->b"


с unset()
310kb 496.59kb 310.38kb 


без unset()

309.91kb 496.52kb 496.52kb 


даже не вникая в специфику работы интерпретатора рнр и то в каком порядке собирается скрипт в байт-код - очевидно что unset() работает.

Может мой РНР более продвинутый или я хз
Антон С.
1316 сообщений
#14 лет назад
>Запускал без

Вот именно, что без все работает.
Смысл в том, что unset иногда не справляется со сложными объектами )
А я сразу сказал, что парсер огромный )
Кирилл Е.
2817 сообщений
#14 лет назад
Нужно смотреть сам парсер, видимо он и оставляет мусор.

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

В этом, можно сказать, и есть недостаток рнр - что на нём, в принципе, может любой кодить - но может и накодить на свою голову и не только ) вот в С - посложнее будет, там одни указатели чего стоят.