Вопрос

Похоже, Doctrine занимает более 4 МБ оперативной памяти для выполнения одного простого запроса:

print memory_get_peak_usage()." <br>\n";
$q = Doctrine_Query::create()
    ->from('Directories d')
    ->where('d.DIRECTORY_ID = ?', 5);

$dir = $q->fetchOne();
print $dir['name']." ".$dir['description']."<br>\n";

print memory_get_peak_usage()." <br>\n";

/***************  OUTPUT:  **************************

6393616
testname testdescription
10999648

/***************************************************/

Это находится в тестовой базе данных с очень небольшим количеством данных в ней - элемент, который я запрашиваю, не содержит никаких данных, кроме тех, что отображаются здесь.

Есть ли потенциально что-то неправильное в том, как я настроил систему, или это стандартное использование памяти для Doctrine?

Это было полезно?

Решение

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


В качестве теста я привел краткий пример с очень простой таблицей (всего четыре поля).

Вот соответствующий код :

var_dump(number_format(memory_get_peak_usage()));

$test = Doctrine::getTable('Test')->find(1);

var_dump(number_format(memory_get_peak_usage()));

Когда я делаю это, у меня получается такой результат :

string '1,316,088' (length=9)
string '2,148,760' (length=9)

Учитывая, что таблица действительно простая и что я извлекаю только одну строку, мне это тоже кажется "многовато" - но это вполне согласуется с тем, что вы получаете, и с тем, что я видел в других проектах :-(


Если вам нужно только отобразить свои данные, а не работать с ними (т. Е. обновить / удалить / ...), решением может быть не извлечение сложных объектов, а только простой массив :

$test = Doctrine::getTable('Test')->find(1, Doctrine::HYDRATE_ARRAY);

Но, в данном случае, на самом деле это не имеет большого значения:-( :

string '1,316,424' (length=9)
string '2,107,128' (length=9)

Разница всего в 40 КБ - ну, с большими объектами / большим количеством строк это все равно может быть хорошей идеей...


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


О, кстати :Я выполнил этот тест на PHP 5.3.0 ;возможно, это может повлиять на объем используемой памяти...

Другие советы

Я согласен с ответом Романа - использование кеша OpCode является обязательным условием при использовании больших библиотек / библиотек.

Пример, связанный с кэшированием OpCode

Я недавно принял использование Doctrine с Zend Framework и мне было любопытно использовать память - поэтому, как и OP, я создал метод, использующий критерии, аналогичные тесту OP, и провел его в качестве общего теста, чтобы увидеть, какой пик ZF + Doctrine использование памяти будет.

Я получил следующие результаты:

Результат без APC:

10.25 megabytes
RV David
16.5 megabytes

Результат с APC:

3 megabytes
RV David
4.25 megabytes

Кэширование кода операции имеет очень важное значение.

Ну, откуда это использование памяти? Как отметил Паскаль МАРТИН, гидратация массива не имеет большого значения, что логично, поскольку речь идет только о нескольких записях.

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

Если у вас нет настроенного APC, тогда да, что-то не так с настройкой вашей системы. Даже не начинайте измерять производительность и ожидать хороших результатов с любой большой библиотекой php без кеша кода операции, такого как APC. Это не только ускорит выполнение, но и сократит использование памяти как минимум на 50% для всех загрузок страницы, кроме самой первой (где APC сначала необходимо кэшировать байт-коды).

И 4MB в вашем простом примере действительно пахнет как no-APC, в противном случае он был бы немного выше.

Будьте осторожны с fetchOne () в Doctrine Query. Этот вызов функции не добавит «Предел 1» на SQL

Если вам просто нужно получить одну запись из БД, убедитесь, что:

$q->limit(1)->fetchOne() 

Использование памяти на больших столах огромно.

Вы могли видеть, что fetchOne () будет сначала извлекать данные из БД в виде коллекции, а затем возвращать первый элемент.

public function fetchOne($params = array(), $hydrationMode = null)
{
    $collection = $this->execute($params, $hydrationMode);

    if (is_scalar($collection)) {
        return $collection;
    }

    if (count($collection) === 0) {
        return false;
    }

    if ($collection instanceof Doctrine_Collection) {
        return $collection->getFirst();
    } else if (is_array($collection)) {
        return array_shift($collection);
    }

    return false;
}

Doctrine предоставляет функцию free() для Doctrine_Record, Doctrine_Collection и Doctrine_Query, которая устраняет циклические ссылки на эти объекты, освобождая их для сборки мусора.Подробная информация..

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

  • $record-> free (true) – будет выполнять глубокое освобождение, вызовы free () для всех отношений тоже
  • $collection-> free() – это освободит все ссылки на коллекции
  • Doctrine_Manager:: соединение ()-> очистить() / clear() – очистить соединение (и удалить записи карты идентификации)
  • $запрос->бесплатно()

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

  • Какую версию Doctrine вы используете?
  • Используете ли вы автозагрузчик?

В Doctrine 1.1 поведение автоматической загрузки по умолчанию называется "агрессивным", что означает, что оно загружает все ваши классы модели, даже если вы используете только один или два по какому-либо конкретному запросу.Установка для такого поведения значения "консервативный" уменьшила бы использование памяти.

Я только что сделал " демонизирован " скрипт с symfony 1.4 и установкой следующего остановил захват памяти:

sfConfig::set('sf_debug', false);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top