Magento клиент Сохраните утечку памяти
-
22-10-2019 - |
Вопрос
Я пытаюсь отредактировать данные клиентов в объеме (пара тысяч записей), а 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()
Методы и удалите модель из переменной в каждом случае.