Есть ли способ узнать, какие объекты и сколько у меня в памяти? - PullRequest
6 голосов
/ 06 октября 2011

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

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

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

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

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

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

Ответы [ 3 ]

2 голосов
/ 07 октября 2011

30 000 объектов для гидратации - это довольно много.Doctrine 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 голосов
/ 06 октября 2011

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

get_defined_vars();

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

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

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

Кроме того, если загружено две вещи, вы получаете это в начале и в конце своего кода и решаете разницу.

0 голосов
/ 06 октября 2011

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

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

...