Magento客户保存内存泄漏
-
22-10-2019 - |
题
我正在尝试批量编辑客户数据(几千条记录),但 Magento 不断耗尽可用内存来运行脚本。
经过一些测试后 memory_get_usage()
罪魁祸首似乎是 $customer->save()
方法似乎每次保存都会占用 5M 内存,但完成后不会释放它。
因此,当循环数千条记录时,它会耗尽内存。
这是我到目前为止所尝试过的:
$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
}
任何帮助将不胜感激。
附注我不确定是否 clearInstance()
函数(在 Mage_Core_Model_Abstract 中)可以做任何事情,如果有人对此有一些见解,如果它共享,我们将不胜感激:)
解决方案
我认为这与核心PHP问题有关,如果没有对核心Magento文件进行大量修改,该问题不容易解决。
完成此操作的唯一方法是使用解决方法:
我提议:
一个。如果从浏览器中调用了这一点,我将进行一个单独的Ajax呼叫,正如@Julien Lacal在他的答案中推荐的那样。
b。如果这一切都完成了服务器端,我将将其分解为两个脚本,其中1个。 createCustomerAddress
功能,使用邮政参数。然后,应使用第一个脚本中的卷曲来调用第二个脚本,以使第二个脚本的每个实例都孤立地运行,并且不受内存泄漏的影响。
其他提示
仅一旦没有引用该变量/对象,才会发布内存。我怀疑 - 一旦确认我的答案,Magento中的事件系统将模型的实例传递给了观察者,因此在内存中对其进行了引用。
但这是一个有据可查的问题。 (我在2011年发表的评论 http://www.magentocommerce.com/boards/viewthread/26561/).
我相信这是 Magento 所有平台和版本的一个已知问题。 unset()
或者 clearInstance()
不会有任何影响。 Mage::getModel()
在我遇到的所有实例(客户、产品、订单等)中都存在内存泄漏。我发现的唯一方法是在处理大量对象创建时,如果可能的话(可能不适合您)使用集合。当你的进程完成时,内存将被释放。
你的内存不足了吗?这通常不是问题,除非您是问题。如果内存不足,也许您可以尝试将批量进程分解为扩展中的单独运行。如果这是在 shell 脚本中,那么很容易将其分解。只需创建两个或多个文件,并使用预定义的客户范围逐个运行它们 entity_id
s。
一个好的解决方法是为批量客户导入构建自己的管理模块,并让其使用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()
方法并在每种情况下从变量中删除模型。