用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 = null
比unset()
对应的要快一点:更新一个符号表项似乎比删除它快。
- 当您尝试使用不存在的(
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)