Magento / Zend Framework中的内存泄漏

时间:2013-04-13 15:43:13

标签: php magento zend-framework

运行这个简单的脚本时,我得到下面发布的输出。 这让我觉得我的代码或Zend Framework / Magento堆栈中都存在内存泄漏。迭代任何类型的Magento集合时会发生此问题。 我有什么遗漏或做错了吗?

脚本:

$customersCollection = Mage::getModel('customer/customer')->getCollection();

foreach($customersCollection as $customer) {
  $customer->load();
  $customer = null;
  echo memory_get_usage(). "\n";
}

输出:

102389104
102392920
...
110542528
110544744

5 个答案:

答案 0 :(得分:7)

您的问题是,当您可以通过集合查询加载必要的数据时,每次迭代都会发出相当昂贵的查询:

$collection = Mage::getResourceModel('customer/customer_collection')->addAttributeToSelect('*');

将执行相同操作,但只能在一个查询中执行。这种方法的警告是,如果customer_load_beforecustomer_load_after事件有任何自定义事件观察者(这些事件没有核心观察者),则需要为每个数据模型手动运行观察者。

编辑:信用osonodoar以发现不正确的类引用(客户/客户与客户/客户集合)

答案 1 :(得分:3)

对象(或其他值)的内存只能在PHP进程中的任何位置都没有引用时释放。在您的情况下,行$customer = null仅将对该对象的引用数减少一个,但它不会使其达到零。

如果你考虑一个更简单的循环,这可能会变得更清晰:

$test = array('a' => 'hello');
foreach ( $test as $key => $value )
{
    // $value points at the same memory location as $test['a']
    // internally, that "zval" has a "refcount" of 2

    $value = null;
    // $value now points to a new memory location, but $test['a'] is unnaffected
    // the refcount drops to 1, but no memory is freed
}

因为你正在使用对象,所以有一个额外的转折 - 你可以修改循环内的对象而不创建它的新副本:

$test = array('a' => new __stdClass);
// $test['a'] is an empty object

foreach ( $test as $key => $value )
{
    // $value points at the same object as $test['a']
    // internally, that object has a "refcount" of 2

    $value->foo = "Some data that wasn't there before";
    // $value is still the same object as $test['a'], but that object now has extra data
    // This requires additional memory to store that object

    $value = null;
    // $value now points to a new memory location, but $test['a'] is unnaffected
    // the refcount drops to 1, but no memory is freed
}

// $test['a']->foo now contains the string assigned in the loop, consuming extra memory

在您的情况下,->load()方法可能会依次扩大$customersCollection每个成员中的数据量,每个成员需要更多内存。在循环之前和之后检查$customersCollection可能会证实这一点。

答案 2 :(得分:0)

首先,当取消设置变量使用unset($ variable)而不是$ variable = null时。它基本上是一样的,但是你的意图更清楚。

其次,PHP意味着死亡 - 内存泄漏不是一个大问题,因为PHP请求可能持续几秒钟,然后进程终止并且它正在使用的所有内存都被释放用于下一个请求。除非您遇到扩展问题,否则无需担心。

编辑:这并不是说不要担心代码的质量,但对于这样的事情,除非造成问题,否则最有可能不值得尝试阻止它发生。

答案 3 :(得分:0)

处理内存泄漏的其他方法是在循环中调用exec并让exec函数执行导致内存泄漏的作业部分。

因此,一旦它完成其部分并终止该exec内的所有内存泄漏将被释放。

因此,在大量迭代的情况下,这种记忆损失会继续增加,否则将会非常谨慎。

答案 4 :(得分:0)

@benmarks响应在这里是正确的方法,因为在循环中调用load()是一个非常昂贵的调用。

调用$ customer-> load()将逐步分配$ customersCollection引用的内存,该内存在循环结束前不会被释放。

但是,如果因任何原因需要调用load(),则下面的代码不会泄漏内存,因为GC会在每次迭代中释放模型分配的所有内存。

$customersCollection = Mage::getModel('customer/customer')->getCollection();

foreach($customersCollection as $customer) {
    $customerCopy = Mage::getModel('customer/customer')->load($customer->getId());

    //Call to $customerCopy methods

    echo memory_get_usage(). "\n";
}