Вопрос

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

После некоторого тестирования с memory_get_usage() Виновником, кажется, является $customer->save() Метод, который, кажется, занимает 5 м памяти для каждого сохранения, но не выпускает его, когда сделано.

В результате, когда он проходит через пару тысяч записей, он запускает память.

Вот что я пробовал до сих пор:

$customer->clearInstance()

unset($customer)

Это, похоже, не помогает.

Ниже мой код:

public function createCustomerAddress($customerAddressData, $email){
     $customer = Mage::getModel('customer/customer');

     $customer->setWebsiteId(Mage::app()->getWebsite()->getId());
     $customer->loadByEmail($email);

     $address   = Mage::getModel('customer/address');

     $address->addData($customerAddressData);
     $customer->addAddress($address);
     unset($address);
     try{
         $customer->save();
     }catch (Exception $e){
         var_dump($customerAddressData);
         var_dump($e->getMessage());
     }
    echo "\n" . "Before unsetting \n" . memory_get_usage() . "\n";
    $customer->clearInstance();
    unset($customer);
    echo "\n" . "After  \n" . memory_get_usage() . "\n";  // no difference than before
}

Любая помощь будет очень оценена.

ps я не уверен, если clearInstance() Функция (в mage_core_model_abstract) что -то делает, если у кого -то есть какое -то представление об этом, было бы очень оценено, если он обменивается :)

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

Решение

Я думаю, что это связано с основной проблемой PHP, которая нелегко разрешить без обширных модификаций основных файлов Magento.

Единственный способ сделать это - использовать обходной путь:

Я предлагаю:

а Если бы это вызвано из браузера, я бы сделал отдельный звонок Ajax, как рекомендовал @Julien Lacal в своем ответе.

беременный Если все это будет сделано на стороне сервера, я бы разбил это до двух сценариев, с 1. Один, который итерация по существующему списку клиентов и 2. один, который вызывает createCustomerAddress функция, используя Post Params. Затем следует назвать второй сценарий, используя Curl из первого сценария, так что каждый экземпляр второго сценария выполняется изолированно, и не влияет утечка памяти.

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

Память выпускается только после того, как нет ссылок на эту переменную/объект. Я подозреваю - и отредактирует мой ответ, как только подтвердил, что система событий в Magento передает экземпляр модели наблюдателю, и поэтому в памяти есть ссылка на нее.

Но это хорошо задокументированная проблема. (тот, который я прокомментировал в 2011 году http://www.magentocommerce.com/boards/viewthread/26561/).

Я считаю, что это известная проблема на всех платформах и версиях Magento. unset() или же clearInstance() не будет иметь никакого эффекта. Mage::getModel() Утечка памяти во всех случаях, с которыми я сталкивался (клиент, продукты, заказы и т. Д.). Единственный способ обойти, который я обнаружил, - это использовать коллекцию вместо этого, если это возможно (может быть не применимо для вас), при работе с большим количеством произведений объектов. Когда ваш процесс будет завершен, память будет выпущена.

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

Хорошим обходным пути будет создание своего собственного модуля администратора для импорта клиента и использование его вызовов AJAX для контроллера для импорта данных в небольших наборах. Таким образом, вы не закончите память, потому что он запустит новый процесс каждый раз, когда вы делаете этот вызов AJAX вместо постоянно распределять память из -за Mage::getModel('customer/address')

Кажется, я нашел серьезную утечку памяти при звонке Model::save()

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

$this->_getResource()->addCommitCallback(array($this, 'afterCommitCallback'))

Таким образом, модель добавляется в статический параметр $_commitCallbacks. Анкет Метод будет удален, если уровень транзакции установлен только на ноль.

Чтобы решить это либо добавить следующий код в свою собственную модель ресурса:

public function addCommitCallback($callback)
{
    return $this;
    //return parent::addCommitCallback($callback);
}

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

Другая (лучшая) возможность - перезаписать commit() а также rollback() Методы и удалите модель из переменной в каждом случае.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с magento.stackexchange
scroll top