Use unset() to save memory

时间:2015-06-30 13:42:01

标签: php memory-management unset

Background: I need to parse some large XML files line by line and save the infos in associative arrays. I'm parsing it with DOMDocument.

Even the memory saving not being an essential requirement, I'm trying to use the unset() to save some memory during my script execution to avoid any possible error of this type without use ini_set approaches and things like this.

See the code below to see my approach to do this:

        //using DOMDocument to get the tag product
        $countriesCovered = array();
        $countriesCoveredTag = $productTag->getElementsByTagName('countriesCovered')->item(0);
        $countries = $countriesCoveredTag->getElementsByTagName('country');
        foreach ($countries as $countryTag) {
            $country = array();
            $country['name'] = $countryTag->getElementsByTagName('name')->item(0)->nodeValue;
            $country['code'] = $countryTag->getElementsByTagName('code')->item(0)->nodeValue;
            $countriesCovered[] = $country;
            unset ($country);
        }

To me, it's logical that I'm saving memory doing this, since I'm copying the variable country to the array countriesCovered and unset country (I mean freeing memory that was allocated to country, right?). However, I didn't found anything to ensure this in the Documentation, so I can't ensure that I'm really saving memory.

Thus, Am I doing this in the right way? Is it needed even with the Garbage Collection? I think that perhaps the unset might be totally worthless, but I can't ensure this.

3 个答案:

答案 0 :(得分:2)

This is not entirely true. PHP does not have any biuld-in memory management mechanism. It entirely relies on garbage collection, so to truly free any memory, you need to call garbage collection process. Unset actually only decrements internal reference counter and does nothing with the memory itself. Once reference counter reaches zero, the garbage collector will free the memory.

You may want to check how garbage collector may affect application performance in composer's case study. Check out how one line change caused composer to run 70% faster

For your case unset will actually do nothing. PHP internally does not copy variable immediatelly after assignment. It creates a reference instead and incerements internal reference counter. The variable is really copied only when it is modified after assignment. So your $country variable is pointing to the same memory address as the item in $countriesCovered array.

答案 1 :(得分:1)

You can do this without temporary variable

$countriesCovered[] = [
    'name' => $countryTag->getElementsByTagName('name')->item(0)->nodeValue,
    'code' => $countryTag->getElementsByTagName('code')->item(0)->nodeValue
]

答案 2 :(得分:1)

正如Alexander Madyuskin所说,你不需要在循环中声明变量;您可以直接将变量设置到主关联数组中。无论如何,你无论如何都不会失去太多内存,因为你只是真正创建了几个引用(而不是多个值)。

即使您正在操作该值,这将导致生成(而不是多个引用)的多个副本,但每次迭代结束时局部变量都超出范围无论如何;所以不需要打电话。

一般垃圾收集

关于垃圾收集,你要问的更广泛的一点是:

  

垃圾收集器会在变量时自行释放内存   超出范围

当没有可访问的变量时,变量被认为已超出范围;所以在foreach循环或if条件中定义的变量在迭代结束时或有条件的情况下都有资格收集。

示例:

$externalArr = [];
while ($x=0; $x<50; $x++) {
  $internalArr = []
  $externalArr[] = $x;
  $internalArr[] = $x;

  // End of loop, $internalArr is now eligible for 
  // garbage collection regardless of whether it is unset
}

// The $externalArr is still in scope, so if we want it to be 
// collected, we have to manually unset it, or else it will exist 
// until the end of the script execution
unset($externalArr);