Есть ли способ узнать, какие объекты и сколько их у меня в памяти?


У меня есть php-скрипт, который использует Doctrine2 и Zend для вычисления некоторых вещей из базы данных и отправки некоторых электронных писем для 30.000 пользователей.

В моем скрипте происходит утечка памяти, и я хочу знать, какие объекты потребляют эту память, и, если возможно, кто хранит ссылку на них (таким образом, не позволяя им быть освобожденными).

Я использую php 5.3.x, поэтому простые циклические ссылки не должны быть проблемой.

Я пытался использовать возможности трассировки xdebug, чтобы получить mem_delta без успеха (слишком много данных).

Я попытался вручную добавить memory_get_usage до и после важных функций. Но единственный вывод, который я сделал, заключался в том, что я теряю около 400 тысяч на пользователя и 3000 пользователей, что дает мне 1 Гб, который у меня есть.

Существуют ли какие-либо другие способы узнать, где и почему происходит утечка памяти? Спасибо

Author: Lightness Races in Orbit, 2011-10-06

3 answers

Вы можете попробовать отправить, скажем, 10 электронных писем, а затем вставить это

get_defined_vars();

Http://nz.php.net/manual/en/function.get-defined-vars.php

В конце сценария или после отправки электронного письма (в зависимости от того, как настроен ваш код).

Это должно сказать вам, что все еще загружено, и что вы можете отменить/превратить в ссылку.

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

 2
Author: P4ul, 2011-10-05 23:39:11

30.000 объектов для гидратации - это довольно много. Доктрина 2 стабильна, но есть некоторые ошибки, поэтому я не слишком удивлен вашими проблемами с утечкой памяти.

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

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

Очень важно, чтобы скрипт распознавал, какие объекты обрабатываются, чтобы его можно было перезапустить без каких-либо проблем и возобновить нормальную работу без повторной отправки электронных писем.

$batchSize = 20;
$i = 0;
$q = $em->createQuery('select u from MyProject\Model\User u');
$iterableResult = $q->iterate();
while (($row = $iterableResult->next()) !== false) {
    $entity = $row[0];

    // do stuff with $entity here
    // mark entity as processed

    if (($i % $batchSize) == 0) {
        $em->flush(); 
        $em->clear();

        gc_collect_cycles();
    }
    ++$i;
}

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

 2
Author: Max, 2011-10-07 18:07:41

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

Http://martinfowler.com/eaaCatalog/identityMap.html

 0
Author: Joey Rivera, 2011-10-06 01:42:44