用PHP释放内存更好些:unset()或$ var = null

我意识到第二个避免了函数调用的开销( 更新 ,实际上是一个语言结构),但是知道一个是否比另一个更好会是有趣的。 我一直在使用unset()进行大部分编码工作,但是最近我通过一些可以从网上找到的使用$var = null尊敬类进行了研究。

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

它在2009年的未设置手册页面中提到:

unset()做它的名字说 – 取消设置一个变量。 它不强制立即释放内存。 PHP的垃圾收集器将会在它看到适合的意图时尽快实现,因为无论如何,这些CPU周期是不需要的,或者是在脚本运行内存不足之前,无论先发生什么。

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

(从2013年起,这个未unset手册页就不再包含该部分)

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


“ 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); Outputs: NULL 

看来$a = nullunset()对应的要快一点:更新一个符号表项似乎比删除它快。


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

unset实际上不是一个函数,而是一个语言结构 。 它不是一个函数调用,而不是一个return或一个include

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

通过对一个变量执行unset(),你已经基本上标记了“垃圾收集”的变量(PHP实际上并没有一个,但是举例来说),所以内存不是立即可用的。 变量不再包含数据,但堆栈保持较大的大小。 执行null方法会立即丢弃数据并收缩堆栈内存。

这是从个人经验和其他人的。 请参阅unset()函数的注释。

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

 <?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 / Example#1中给出的microtime_float示例。

它与数组元素有所不同。

考虑这个例子

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

在这里,关键的“测试”依然存在。 但是,在这个例子中

 $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 pointer to any var print $a; // 5 $a = 5; $b = &$a; $b = null; //rewrite value of $b (and $a) print $a; // nothing, because $a = null 

对于对象,特别是在延迟加载的场景中,应该考虑垃圾收集器在闲置的CPU周期中运行,所以假设在很多对象加载时遇到麻烦,很小的时间处罚将解决内存释放。

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

在生产服务器上测试过,原来这个工作消耗了50MB,然后就停了下来。 在使用纳秒睡眠之后,14MB是恒定的记忆消耗量。

应该说这取决于可能会从PHP版本更改为版本的GC行为。 但它适用于PHP 5.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); ... 

我仍然怀疑这一点,但我已经在我的脚本尝试过,我正在使用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代码之前,它给了我:160200然后我试图改变它$sql = NULL ,它给我:160224 🙂

但是,当我不使用unset()或NULL,xdebug给我160144作为内存使用

所以,我认为给行使用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

现在我已经很久没有使用了。

在代码中更好地实践这样做,以便立即取消所有已经用作数组的变量。

 $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)