什么是更好的释放内存与PHP: unset()或$var = null

我意识到第二种方法避免了函数调用的开销(更新,实际上是一种语言构造),但知道其中一种是否比另一种更好会很有趣。我的大部分代码都使用unset(),但最近我浏览了一些在网上找到的使用$var = null的体面类。

是否有一个首选的,理由是什么?

214454 次浏览

通过对变量执行unset()操作,您实际上已经将变量标记为“垃圾收集”(PHP实际上并没有这样的功能,但为了举例说明),因此内存不能立即可用。该变量不再存储数据,但堆栈仍然保持较大的大小。执行null方法几乎会立即丢弃数据并缩小堆栈内存。

这是我个人的经验,也是别人的经验。参见unset()函数在这里的注释。

我个人在循环的迭代之间使用unset(),这样我就不必在大小上有堆栈的延迟。数据消失了,但足迹还在。在下一次迭代时,内存已经被php占用,因此可以更快地初始化下一个变量。

它在在2009年取消设置手册页中提到过:

unset()做的正如它的名字所说-取消设置一个变量。它不会强制立即释放内存。PHP的垃圾收集器将在它认为合适的时候执行它——根据意图,尽快执行,因为这些CPU周期无论如何都不需要,或者在脚本耗尽内存之前执行,无论先发生什么。

如果你正在执行$whatever = null;,那么你正在重写变量的数据。您可能会更快地释放/收缩内存,但它可能会更快地从真正需要它们的代码中窃取CPU周期,从而导致更长的总体执行时间。

(自2013年起,unset手册页不再包含该部分)

注意,在php5.3之前,如果你有循环引用中的两个对象,比如在父子关系中,在父对象上调用unset()将不会释放用于子对象中父引用的内存。当父对象被垃圾回收时,内存也不会被释放。


问题"unset和= null的区别"详细说明一些区别:


unset($a)也从符号表中删除$a;例如:

$a = str_repeat('hello world ', 100);
unset($a);
var_dump($a);

输出:

Notice: Undefined variable: a in xxx
NULL

但是当使用$a = null时:

$a = str_repeat('hello world ', 100);
$a = null;
var_dump($a);

输出:

NULL

$a = null似乎比unset()快一点:更新符号表项似乎比删除它快。


  • 当您尝试使用不存在(unset)变量时,将触发一个错误,变量表达式的值将为null。(因为,PHP还应该做什么?每个表达式都需要产生某个值。)
  • 一个赋值为null的变量仍然是一个完全正常的变量。

unset实际上不是一个函数,而是一个语言结构。它与returninclude一样都不是函数调用。

除了性能问题,使用unset可以使代码的意图更加清晰。

它对数组元素有影响。

考虑这个例子

$a = array('test' => 1);
$a['test'] = NULL;
echo "Key test ", array_key_exists('test', $a)? "exists": "does not exist";

这里,键“test”仍然存在。然而,在这个例子中

$a = array('test' => 1);
unset($a['test']);
echo "Key test ", array_key_exists('test', $a)? "exists": "does not exist";

密钥不再存在。

对于通过引用复制的变量,它的工作方式不同:

$a = 5;
$b = &$a;
unset($b); // just say $b should not point to any variable
print $a; // 5


$a = 5;
$b = &$a;
$b = null; // rewrites value of $b (and $a)
print $a; // nothing, because $a = null

对于对象,特别是在惰性加载场景中,应该考虑垃圾收集器运行在空闲的CPU周期中,因此假设您遇到了麻烦,当大量对象加载时,小时间惩罚将解决内存释放问题。

使用time_nanosleep使GC收集内存。 将变量设置为null是可取的

在生产服务器上测试,最初作业消耗50MB,然后停止。 在使用nanosleep后,14MB是恒定的内存消耗 有人会说这取决于GC行为,这可能会在不同版本的PHP中发生变化。 但它在php5.3上运行良好

如。此示例(代码取自VirtueMart2谷歌提要)

for($n=0; $n<count($ids); $n++)
{
//unset($product); //usefull for arrays
$product = null
if( $n % 50 == 0 )
{
// let GC do the memory job
//echo "<mem>" . memory_get_usage() . "</mem>";//$ids[$n];
time_nanosleep(0, 10000000);
}


$product = $productModel->getProductSingle((int)$ids[$n],true, true, true);
...
<?php
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
$a = NULL;
}
$elapsed = microtime(true) - $start;


echo "took $elapsed seconds\r\n";






$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
unset($a);
}
$elapsed = microtime(true) - $start;


echo "took $elapsed seconds\r\n";
?>

根据这一点,“= null”似乎更快。

PHP 5.4结果:

  • 花了0.88389301300049秒
  • 耗时2.1757180690765秒

PHP 5.3结果:

  • 耗时1.7235369682312秒
  • 用时2.9490959644318秒

PHP 5.2结果:

  • 花了3.0069220066071秒
  • 耗时4.7002630233765秒

PHP 5.1结果:

  • 花了2.6272349357605秒
  • 耗时5.0403649806976秒

在PHP 5.0和4.4中,情况开始有所不同。

5.0:

  • 花了10.038941144943秒
  • 耗时7.0874409675598秒

4.4:

  • 耗时7.5352551937103秒
  • 花了6.6245851516724秒

请记住,microtime(true)在PHP 4.4中不起作用,因此我必须使用php.net/microtime /示例#1中给出的microtime_float示例。

我仍然怀疑这一点,但我已经在我的脚本中尝试过,我正在使用xdebug来了解它将如何影响我的应用程序内存使用。 脚本是这样设置在我的函数:

function gen_table_data($serv, $coorp, $type, $showSql = FALSE, $table = 'ireg_idnts') {
$sql = "SELECT COUNT(`operator`) `operator` FROM $table WHERE $serv = '$coorp'";
if($showSql === FALSE) {
$sql = mysql_query($sql) or die(mysql_error());
$data = mysql_fetch_array($sql);
return $data[0];
} else echo $sql;
}
我在return代码之前添加了unset,它给我:160200 然后我尝试用$sql = NULL改变它,它给我:160224:)

但有一些独特的比较,当我不使用unset()或NULL, xdebug给我160144作为内存使用量

所以,我认为给line使用unset()或NULL将添加进程到您的应用程序,它将更好地保持原点与您的代码和减少变量,你正在使用尽可能有效。

如果我说错了请指正,谢谢

我为unset=null创建了一个新的性能测试,因为正如注释中提到的,这里写的有一个错误(重新创建元素)。 我使用了数组,正如你所看到的,现在已经无关紧要了
<?php
$arr1 = array();
$arr2 = array();
for ($i = 0; $i < 10000000; $i++) {
$arr1[$i] = 'a';
$arr2[$i] = 'a';
}


$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$arr1[$i] = null;
}
$elapsed = microtime(true) - $start;


echo 'took '. $elapsed .'seconds<br>';


$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
unset($arr2[$i]);
}
$elapsed = microtime(true) - $start;


echo 'took '. $elapsed .'seconds<br>';
但是我只能在PHP 5.5.9服务器上测试它,结果如下: -耗时4.4571571350098秒 -花了4.4425978660583秒

出于可读性的原因,我更喜欢unset

unset代码如果没有释放即时内存仍然是非常有用的,这将是一个很好的实践,每次我们在退出方法之前传递代码步骤时都这样做。请注意,这不是关于释放即时内存。 直接内存是CPU的,辅助内存是RAM

这也解决了防止内存泄漏的问题。

请看这个链接 http://www.hackingwithphp.com/18/1/11/be-wary-of-garbage-collection-part-2 < / p >

我使用unset已经很长时间了。

更好的做法是在代码中立即取消所有已经作为数组使用的变量。

$data['tesst']='';
$data['test2']='asdadsa';
....
nth.

just unset($data);来释放所有变量的使用。

请参阅相关主题取消设置

在PHP中取消变量设置有多重要?< / >

(错误)

郑重声明,不包括花费的时间:

<?php
echo "<hr>First:<br>";
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";
echo memory_get_peak_usage() . "<br>\n";
echo "<hr>Unset:<br>";
unset($x);
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";
echo memory_get_peak_usage() . "<br>\n";
echo "<hr>Null:<br>";
$x=null;
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";
echo memory_get_peak_usage() . "<br>\n";


echo "<hr>function:<br>";
function test() {
$x = str_repeat('x', 80000);
}
echo memory_get_usage() . "<br>\n";
echo memory_get_peak_usage() . "<br>\n";


echo "<hr>Reasign:<br>";
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";
echo memory_get_peak_usage() . "<br>\n";

它返回

First:
438296
438352
Unset:
438296
438352
Null:
438296
438352
function:
438296
438352
Reasign:
438296
520216 <-- double usage.

结论,空内存和未设置空闲内存都是预期的(不仅在执行结束时)。另外,对变量重新赋值会在某个点上将值保存两次(520216对438352)

PHP 7已经着手解决这类内存管理问题,并将其使用减少到最小。

<?php
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
$a = NULL;
}
$elapsed = microtime(true) - $start;


echo "took $elapsed seconds\r\n";


$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
unset($a);
}
$elapsed = microtime(true) - $start;


echo "took $elapsed seconds\r\n";


?>

PHP 7.1输出:

花费了0.16778993606567秒 花了0.16630101203918秒

代码示例从评论

echo "PHP Version: " . phpversion() . PHP_EOL . PHP_EOL;


$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
$a = NULL;
}
$elapsed = microtime(true) - $start;


echo "took $elapsed seconds" . PHP_EOL;






$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
unset($a);
}
$elapsed = microtime(true) - $start;


echo "took $elapsed seconds" . PHP_EOL;

运行在集装箱码头工人从映像php:7.4-fpm和其他..

PHP Version: 7.4.8
took 0.22569918632507 seconds null
took 0.11705803871155 seconds unset
took 0.20791196823121 seconds null
took 0.11697316169739 seconds unset


PHP Version: 7.3.20
took 0.22086310386658 seconds null
took 0.11882591247559 seconds unset
took 0.21383500099182 seconds null
took 0.11916995048523 seconds unset


PHP Version: 7.2.32
took 0.24728178977966 seconds null
took 0.12719893455505 seconds unset
took 0.23839902877808 seconds null
took 0.12744522094727 seconds unset


PHP Version: 7.1.33
took 0.51380109786987 seconds null
took 0.50135898590088 seconds unset
took 0.50358104705811 seconds null
took 0.50115609169006 seconds unset


PHP Version: 7.0.33
took 0.50918698310852 seconds null
took 0.50490307807922 seconds unset
took 0.50227618217468 seconds null
took 0.50514912605286 seconds unset


PHP Version: 5.6.40
took 1.0063569545746 seconds null
took 1.6303179264069 seconds unset
took 1.0689589977264 seconds null
took 1.6382601261139 seconds unset


PHP Version: 5.4.45
took 1.0791940689087 seconds null
took 1.6308979988098 seconds unset
took 1.0029168128967 seconds null
took 1.6320278644562 seconds unset


但是,再举一个例子:

<?php
ini_set("memory_limit", "512M");


echo "PHP Version: " . phpversion() . PHP_EOL . PHP_EOL;


$start = microtime(true);
$arr = [];
for ($i = 0; $i < 1000000; $i++) {
$arr[] = 'a';
}
$arr = null;
$elapsed = microtime(true) - $start;


echo "took $elapsed seconds" . PHP_EOL;






$start = microtime(true);
$arr = [];
for ($i = 0; $i < 1000000; $i++) {
$arr[] = 'a';
}
unset($arr);
$elapsed = microtime(true) - $start;


echo "took $elapsed seconds" . PHP_EOL;

结果:

PHP Version: 7.4.8
took 0.053696155548096 seconds
took 0.053897857666016 seconds


PHP Version: 7.3.20
took 0.054572820663452 seconds
took 0.054342031478882 seconds


PHP Version: 7.2.32
took 0.05678391456604 seconds
took 0.057311058044434 seconds




PHP Version: 7.1.33
took 0.097366094589233 seconds
took 0.073100090026855 seconds


PHP Version: 7.0.33
took 0.076443910598755 seconds
took 0.077098846435547 seconds


PHP Version: 7.0.33
took 0.075634002685547 seconds
took 0.075317859649658 seconds


PHP Version: 5.6.40
took 0.29681086540222 seconds
took 0.28199100494385 seconds


PHP Version: 5.4.45
took 0.30513095855713 seconds
took 0.29265689849854 seconds