Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 08.01.2013 06:42:34

Как очистить память при использовании Eloquent ORM

Как очистить память используя  Eloquent ORM, мой маленький тест показал что она не очищается. А мне жизненно необходимо выполнить > 100к более сложных итераций, и только из за того что память почему-то не ощищается, переходить со своих 512 мб, на 2гб, платя в несколько раз больше за VPS не хочется.

<?
    public function memory()
    {
        $text = <<<EOT
       Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text 
EOT;
        echo $text;
        for ($x = 0; $x++ < 10000;) {
            Test::create(array('f_1'=>$text));
            echo $x."\n";
            echo get_file_size(memory_get_usage(true))."\n";
        }
    }

--
$test = new Test; $test->f_1 = $text; $test->save();  тот же результат;

Использование gc_enable() не помогло.

Изменено la2ha (08.01.2013 06:44:44)

Не в сети

#2 08.01.2013 10:46:00

Re: Как очистить память при использовании Eloquent ORM

У тебя сложный запрос(ы)? Для критичных мест вроде таких, где сотни/тысячи запросов на один скрипт, я бы использовал сырые запросы через PHPDB::query().

Если сырых запросов не хочется, то возможная утечка в том, что Eloquent не вызывает PHPclose_cursor() после получения всего результата. Исправить это можно в PHPLaravel\Database\Connection::query() — от PHPexecute() она получает PHPPDOStatement, который затем читается в PHPfetch(), но курсор не закрывается, поэтому запрос и весь его результат остаются висеть в памяти.

Судя по всему исправить это можно только изменением кода ядра напрямую, либо наследованием PHPLaravel\Database\Connection, перекрытием там нужного метода и затем заменой его в PHPDatabase::$connections при запуске скрипта, например:

PHP
// application/start.php
$connection Config::get('database.default');
$config Config::get("database.connections.$connection");
DB::$connections[$connection] = new MyConnection(DB::connect($config), $config);

// алиас в application.config нужно убрать
class DB extends Database {
  
// изначально функция приватная
  
static function connect($config) { return parent::connect($config); }
}

// application/libraries/MyConection.php
class MyConnection extends Laravel\Database\Connection {
  protected function 
fetch($statement$style) {
    
$result parent::fetch($statement$style);
    
$statement->closeCursor();
    return 
$result;
  }
}

Не в сети

#3 08.01.2013 12:32:25

Re: Как очистить память при использовании Eloquent ORM

// алиас в application.config нужно убрать
Не нашел там алиаса на  Laravel\Database\Connection

Куда писать

class DB extends Database {
  // изначально функция приватная
  static function connect($config) { return parent::connect($config); }
}

???
Не в конфиг же!!

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

foreach($this as $item) clear($item) //не так конечно, но суть ясна

А потом подумал что плохо это, в ядро лезть. И очень много классов там учавствует вроде, поэтому подумал уже более мощном VPS по поим подчетам получалось 1 мегабайт за 4 минуты набегает, за сутки следовательно 360 примерно, а скрипт выполняться примерно 3 дня должен. В общем многовато надо ресурсов не на что тратить.

Не в сети

#4 08.01.2013 13:24:13

Re: Как очистить память при использовании Eloquent ORM

  1. Не нашел там алиаса на Laravel\Database\Connection

Алиас DB ⇒ Database, а не Connection. Классы можно куда угодно поместить, хоть в application/libraries, хоть в start.php, всё равно они нужны при запуске.

  1. А вообще спасибо большое, а то я уже отчаялся, после того как пол ночи общался в IRC по этому поводу и ничего не помогало.

Не факт, что это исправит утечку, я сам не пробовал.

  1. А потом подумал что плохо это, в ядро лезть.

В ядро можно лезть, если ты просто ищешь ошибку. Пока не найдёшь можно править любые файлы руками, а как обнаружишь уже будешь думать о том, как это сделать по-нормальному. Если пытаться всё делать по-нормальному без знания, где точно проблема, это будет очень долго, да и смысл?

Если закрытие курсора не поможет, то используй сырые запросы, с ними точно проблем не будет.

  1. а скрипт выполняться примерно 3 дня должен.

Мне кажется его проще перезапускать. Разбей план выполнения на маленькие фрагменты — по часу, например, и пусть он прогресс сохраняет в файл и при каждом запуске (по cron’у, например) начинает с прошлого места. Обычно такая схема более гибкая.

Не в сети

#5 08.01.2013 21:10:48

Re: Как очистить память при использовании Eloquent ORM

Не помогло, написал это напрямую в protected function fetch, точнее не именно это, а так чтоб выполнилось именно это.
Потом выяснил что этот метод вообще не используется.
На счет перезапускать, да, думаю это вариант, правда не самый лучший, т.к. особенность скрипта такая, что ему придятся часа 3 работать просто для того чтоб просто дойти до места на котором остановился - иначе никак, но все же решение.
Но я еще поищу утечку, и если найду - поделюсь.

Не в сети

#6 08.01.2013 21:23:04

Re: Как очистить память при использовании Eloquent ORM

Жалко. А сырые запросы для тебя тоже не вариант?

Не в сети

#7 08.01.2013 23:08:44

Re: Как очистить память при использовании Eloquent ORM

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

DB::query('insert into test (f_1) values ("'.$text.'")');

Изменено la2ha (08.01.2013 23:08:59)

Не в сети

#8 09.01.2013 02:39:27

Re: Как очистить память при использовании Eloquent ORM

Нашел таки, часов 8 на это потратил точно))) Оставлю без комментариев пожалуй.

//application/config/database.php
	/*
	|--------------------------------------------------------------------------
	| Database Query Logging
	|--------------------------------------------------------------------------
	|
	| By default, the SQL, bindings, and execution time are logged in an array
	| for you to review. They can be retrieved via the DB::profile() method.
	| However, in some situations, you may want to disable logging for
	| ultra high-volume database work. You can do so here.
	|
	*/

	'profile' => true,

Не в сети

#9 09.01.2013 10:47:36

Re: Как очистить память при использовании Eloquent ORM

  1. Нашел таки, часов 8 на это потратил точно))) Оставлю без комментариев пожалуй.

Да, это точно без комментариев ☺ Ты на производственном сервере включил профилирование?

Не в сети

#10 09.01.2013 18:37:22

Re: Как очистить память при использовании Eloquent ORM

Оно по умолчанию было включено по мойму.

Не в сети

#11 11.01.2013 04:52:33

Re: Как очистить память при использовании Eloquent ORM

Написал им предложение отрубить его по умолчанию, и его отрубили, так что следующий релиз уже без этого будет.

Не в сети

#12 11.01.2013 10:47:09

Re: Как очистить память при использовании Eloquent ORM

  1. Оно по умолчанию было включено по мойму.

Надо же. Я обычно все настройки пересматриваю сразу как проект начинаю, чтобы особо не зависеть от взглядов разработчиков, которые иногда могут быть неочивидными. У Laravel есть своя специфика — он одновременно подходит для серьёзной разработки, но при этом у него есть какой-то оттенок любительского проекта, проявляющийся в подобных мелочах и способах решения некоторых проблем.

Не в сети

#13 13.01.2013 21:08:40

Re: Как очистить память при использовании Eloquent ORM

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

Так что спасибо! Избавили от плясок с бубнами ☺

Не в сети

Подвал раздела