Утечка памяти в цикле PHP & do / while - PullRequest
3 голосов
/ 09 июля 2010

У меня есть цикл do / while, который проходит по строкам базы данных.Так как он обрабатывает 100 000 строк в течение многих дней, важно следить за потреблением памяти, иначе произойдет сбой.Прямо сейчас каждая итерация добавляет около 4 КБ к использованию памяти скриптом.Я использую memory_get_usage () для мониторинга использования.

Я сбрасываю каждую переменную, используемую в цикле, первым делом в каждой итерации, поэтому я действительно не знаю, что еще я мог сделать.Я предполагаю, что do / while собирает данные с каждой итерации, и это то, что потребляет 4 КБ памяти.Я знаю, что 4 КБ звучит не так уж и много, но вскоре он начинает складываться, когда у вас 100 000 итераций.

Может кто-нибудь предложить другой способ прохождения большого количества строк базы данных или как-то устранить эту "памятьутечка "?

edit Вот ОБНОВЛЕННЫЙ код цикла.Выше всего несколько require_once () s.

$URLs = new URLs_url(db());
$c = new Curl;
$c->headers = 1;
$c->timeout = 60;
$c->getinfo = true;
$c->follow = 0;
$c->save_cookies = false;

do {
    // Get url that hasn't been checked for a week
    $urls = null;

    // Check week old
    $urls = $URLs->all($where)->limit(10);

    foreach($urls as $url) {
        #echo date("d/m/Y h:i").' | Checking '.$url->url.' | db http_code: '.$url->http_code;

        // Get http code    
        $c->url = $url->url;
        $data = $c->get();

        #echo ' - new http_code: '.$data['http_code'];

        // Save info
        $url->http_code = $data['http_code'];
        $url->lastchecked = time();
        $URLs->save($url);
        $url = null;
        #unset($c);
        $data = null;
        #echo "\n".memory_get_usage().' | ';
        echo "\nInner loop memory usage: ".memory_get_usage();
    }
    echo "\nOuter loop memory usage: ".memory_get_usage();

} while($urls);

Некоторые журналы, как потребление памяти ведет себя в обоих циклах:

Inner loop memory usage: 611080
Inner loop memory usage: 612452
Inner loop memory usage: 613788
Inner loop memory usage: 615124
Inner loop memory usage: 616460
Inner loop memory usage: 617796
Inner loop memory usage: 619132
Inner loop memory usage: 620500
Inner loop memory usage: 621836
Inner loop memory usage: 623172
Outer loop memory usage: 545240
Inner loop memory usage: 630680
Inner loop memory usage: 632016
Inner loop memory usage: 633352
Inner loop memory usage: 634688
Inner loop memory usage: 636088
Inner loop memory usage: 637424
Inner loop memory usage: 638760
Inner loop memory usage: 640096
Inner loop memory usage: 641432
Inner loop memory usage: 642768
Outer loop memory usage: 556392
Inner loop memory usage: 640416
Inner loop memory usage: 641752
Inner loop memory usage: 643088
Inner loop memory usage: 644424
Inner loop memory usage: 645760
Inner loop memory usage: 647096
Inner loop memory usage: 648432
Inner loop memory usage: 649768
Inner loop memory usage: 651104
Inner loop memory usage: 652568
Outer loop memory usage: 567608
Inner loop memory usage: 645924
Inner loop memory usage: 647260
Inner loop memory usage: 648596
Inner loop memory usage: 649932
Inner loop memory usage: 651268
Inner loop memory usage: 652604
Inner loop memory usage: 653940
Inner loop memory usage: 655276
Inner loop memory usage: 656624
Inner loop memory usage: 657960
Outer loop memory usage: 578732

Ответы [ 4 ]

2 голосов
/ 09 июля 2010

Этот бит, вероятно, должен произойти только один раз перед циклом:

$c = new Curl;
$c->headers = 1;
$c->timeout = 60;
...
$c->getinfo = true;
$c->follow = 0;
$c->save_cookies = false;

Редактировать: О, все это заключено в цикл do / while. / Facepalm

Редактировать 2: Есть также этот важный бит:

unset ($ class_object) не освобождает ресурсы, выделенные объектом. Если используется в циклах, которые создают и уничтожить объекты, которые могут легко привести к проблеме ресурса. эксплицитно вызвать деструктора, чтобы обойти проблема.

http://www.php.net/manual/en/function.unset.php#98692

Редактировать 3:

Что это? Разве это не может быть как-то перемещено за пределы цикла?

$URLs = new URLs_url(db());

Редактировать 4:

Попробуйте удалить эти строки, пока.

    $url->http_code = $data['http_code'];
    $url->lastchecked = time();
    $URLs->save($url);
0 голосов
/ 09 июля 2010

Это может или не может помочь вам, но когда в 2000 году у меня был клиент, который имел очень медленный интернет и хотел делать все обновления своего веб-сайта cms локально и обновляться, чтобы жить, когда это будет сделано.Тогда на IIS на win xp я не смог найти способ увеличить время ожидания скрипта с 60 секунд, и обычно для обновления понадобилось бы добрых 2 минуты, так что, очевидно, время ожидания истекло.

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

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

Я использовал что-то подобное:*

Начало сценария:

$started = microtime(true);

Тогда это в вашем цикле:

if((microtime(true)-$started) > ($seconds_to_redirect)) {
    //call script with parameter
}

Это все, что я могу придумать.

0 голосов
/ 09 июля 2010

Проблема, вероятно,

$c = new Curl

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

У меня была похожая проблема. Unset не работал - оказалось, что сборка мусора была мусором. Когда я повторно использовал объекты, это было нормально (ну, это сломалось по разным причинам, так что я закончил повторную реализацию в Java).

0 голосов
/ 09 июля 2010

Я думаю, что ваша основная проблема в том, что вы очищаете вещи только во внешнем цикле.

Например,

$c = new Curl будет выделять кучу памяти для каждой итерации внутреннего цикла, но вы только unset используете последний экземпляр. Я бы unset любой материал, который вы можете ($c, $data) на конце внутреннего цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...