使用PHP释放内存有什么好处:unset()或$ var = null

时间:2009-02-25 06:33:41

标签: php

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

是否有首选,是什么原因?

13 个答案:

答案 0 :(得分:226)

unset manual's page in 2009中提到了

  

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

     

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

(自2013年起,unset man page不再包含该部分)

请注意,在php5.3之前,如果你有two objects in circular reference,例如在父子关系中,在父对象上调用unset()将不会释放用于子对象中父引用的内存。 (当父对象被垃圾收集时,也不会释放内存。)(bug 33595


问题“difference between unset and = 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 = null比其unset()对应物快一点:更新符号表条目似乎比删除它更快。


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

答案 1 :(得分:45)

unset实际上不是一个函数,而是语言构造。它不再是returninclude的函数调用。

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

答案 2 :(得分:34)

通过对变量执行unset(),您实际上已经为“垃圾收集”标记了变量(PHP实际上没有一个,但是例如为了这个),因此内存不会立即可用。变量不再容纳数据,但堆栈仍保持较大的大小。执行null方法会丢弃数据并几乎立即缩小堆栈内存。

这也来自个人经验和其他人。请参阅unset()函数here的注释。

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

答案 3 :(得分:27)

<?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";
?>

看起来好像&#34; = null&#34;更快。

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示例。

答案 4 :(得分:18)

它与数组元素有所不同。

考虑这个例子

$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";

钥匙不再存在。

答案 5 :(得分:17)

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

$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

答案 6 :(得分:12)

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

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

在生产服务器上测试,最初该作业消耗了50MB,然后停止了。 使用nanosleep后,14MB是恒定的内存消耗。

应该说这取决于GC行为,可能会从PHP版本变为版本。 但它适用于PHP 5.3。

例如。此示例(代码来自VirtueMart2 google feed)

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);
    ...

答案 7 :(得分:3)

我仍然对此表示怀疑,但我已经在我的脚本中尝试了它,并且我使用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作为内存使用

所以,我认为给线使用unset()或NULL会为你的应用程序添加进程,最好保留你的代码的原点并减少你正在使用的变量尽可能有效。

如果我错了,请纠正我,谢谢

答案 8 :(得分:2)

我为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

答案 9 :(得分:2)

代码示例from comment

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和其他映像的 docker容器中运行。

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

答案 10 :(得分:1)

SKPhysicsContact代码如果没有释放直接内存仍然非常有用,并且每次我们在退出方法之前传递代码步骤时这样做都是一个好习惯。注意它不是要释放即时记忆。 直接内存用于CPU,二级内存是RAM。

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

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

我一直在使用unset很长一段时间。

在代码中更好地练习这样做以实例取消已经用作数组的所有变量。

unset

$data['tesst']=''; $data['test2']='asdadsa'; .... nth. 释放所有变量用法。

请参阅相关主题以取消设置

How important is it to unset variables in PHP?

[错误]

答案 11 :(得分:1)

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 Outpu:

花费0.16778993606567秒 花了0.16630101203918秒

答案 12 :(得分:0)

记录,并排除所需的时间:

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

返回

Array.find

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