使用 unset() 来节省内存
Use unset() to save memory
背景:我需要逐行解析一些大的XML文件并将信息保存在关联数组中。我正在用 DOMDocument
.
解析它
即使内存节省不是基本要求,我也在尝试使用 unset()
在我的脚本执行期间节省一些内存,以避免在不使用 ini_set
的情况下可能出现的此类错误方法和类似的事情。
请参阅下面的代码以了解我执行此操作的方法:
//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);
}
对我来说,这样做节省内存是合乎逻辑的,因为我正在将变量 country
复制到数组 countriesCovered
并取消设置 country
(我的意思是释放分配给 country
的内存,对吗?)。但是,我在 Documentation 中没有找到任何东西来确保这一点,所以我无法确保我真的在节省内存。
因此,
我这样做的方式正确吗?
即使 Garbage Collection 也需要它吗?我认为 unset
可能完全没有价值,但我不能保证这一点。
你可以在没有临时变量的情况下做到这一点
$countriesCovered[] = [
'name' => $countryTag->getElementsByTagName('name')->item(0)->nodeValue,
'code' => $countryTag->getElementsByTagName('code')->item(0)->nodeValue
]
这不完全正确。 PHP 没有任何内置内存管理机制。它完全依赖于垃圾收集,因此要真正释放任何内存,您需要调用垃圾收集过程。 Unset 实际上只是递减内部引用计数器而不对内存本身做任何事情。一旦引用计数器达到零,垃圾收集器将释放内存。
您可能想在 composer 的案例研究中查看垃圾收集器如何影响应用程序性能。查看 how one line change caused composer to run 70% faster
对于你的情况,取消设置实际上什么都不做。 PHP 内部不会在赋值后立即复制变量。它改为创建一个引用并增加内部引用计数器。变量只有在赋值后被修改时才真正被复制。 因此您的 $country 变量指向与 $countriesCovered 数组中的项目相同的内存地址。
正如 Alexander Madyuskin 所说,您不需要在循环内声明变量;你可以直接将变量设置到你的主关联数组中。无论如何,您不会丢失太多内存,因为您实际上只是在创建几个引用(而不是多个值)。
即使您正在操纵值,这会导致创建 value 的多个副本(与多个引用相反),局部变量也会超出范围反正每次迭代结束;所以调用 unset 是不必要的。
一般垃圾收集
您所询问的关于垃圾收集的更广泛的观点是:
The garbage collector will free up memory on its own when variables
fall out of scope
当没有可访问的引用时,变量被认为超出范围;因此在 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);
背景:我需要逐行解析一些大的XML文件并将信息保存在关联数组中。我正在用 DOMDocument
.
即使内存节省不是基本要求,我也在尝试使用 unset()
在我的脚本执行期间节省一些内存,以避免在不使用 ini_set
的情况下可能出现的此类错误方法和类似的事情。
请参阅下面的代码以了解我执行此操作的方法:
//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);
}
对我来说,这样做节省内存是合乎逻辑的,因为我正在将变量 country
复制到数组 countriesCovered
并取消设置 country
(我的意思是释放分配给 country
的内存,对吗?)。但是,我在 Documentation 中没有找到任何东西来确保这一点,所以我无法确保我真的在节省内存。
因此,
我这样做的方式正确吗?
即使 Garbage Collection 也需要它吗?我认为 unset
可能完全没有价值,但我不能保证这一点。
你可以在没有临时变量的情况下做到这一点
$countriesCovered[] = [
'name' => $countryTag->getElementsByTagName('name')->item(0)->nodeValue,
'code' => $countryTag->getElementsByTagName('code')->item(0)->nodeValue
]
这不完全正确。 PHP 没有任何内置内存管理机制。它完全依赖于垃圾收集,因此要真正释放任何内存,您需要调用垃圾收集过程。 Unset 实际上只是递减内部引用计数器而不对内存本身做任何事情。一旦引用计数器达到零,垃圾收集器将释放内存。
您可能想在 composer 的案例研究中查看垃圾收集器如何影响应用程序性能。查看 how one line change caused composer to run 70% faster
对于你的情况,取消设置实际上什么都不做。 PHP 内部不会在赋值后立即复制变量。它改为创建一个引用并增加内部引用计数器。变量只有在赋值后被修改时才真正被复制。 因此您的 $country 变量指向与 $countriesCovered 数组中的项目相同的内存地址。
正如 Alexander Madyuskin 所说,您不需要在循环内声明变量;你可以直接将变量设置到你的主关联数组中。无论如何,您不会丢失太多内存,因为您实际上只是在创建几个引用(而不是多个值)。
即使您正在操纵值,这会导致创建 value 的多个副本(与多个引用相反),局部变量也会超出范围反正每次迭代结束;所以调用 unset 是不必要的。
一般垃圾收集
您所询问的关于垃圾收集的更广泛的观点是:
The garbage collector will free up memory on its own when variables fall out of scope
当没有可访问的引用时,变量被认为超出范围;因此在 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);