关于PHP的unset:

来源:互联网 发布:易语言挂机锁源码 编辑:程序博客网 时间:2024/06/07 00:10
关于PHP的unset:


关于unset是否真正释放内存的问题,在网上搜了一下,发现一些有意思的研究




1.链接:http://bbs.chinaunix.net/archiver/?tid-1043649.html


这里的代码展示了一下,unset之后,内存实际上并没有减少,而是分配给下一个使用的变量了。另外我计算了一下差值,在第10行算了一下第10行和第2行的差,稳定在712。




[code]
      1 <?php
      2 echo memory_get_usage()."\n";
      3
      4 $a[]='a';
      5 unset($a);
      6 echo memory_get_usage()."\n";
      7
      8 $x[]='n';
      9 unset($x);
     10 echo memory_get_usage()."\n";
     11
     12 $c[]='a';
     13 unset($c);
     14 echo memory_get_usage()."\n";
     15 ?>
[/code]


结果是这样的
50764          --->Start
51152          --->定义$a并释放
51152          --->定义$x并释放
51152          --->定义$c并释放




PHP是解释执行的过程
定义$a一定导致一次内存分配
定义$x也导致内存分配
但内存使用量没有增加为什么  因为$a被释放了 $x使用的内存和$a一样正好使用了$a释放的内存


是不是得出以下结论 :


1  unset释放内存了释放的内存 还被整个脚本占用 以备复用


2  PHP仅在结束时候将全部内存释放掉你不是放文件描述 数据库链接 也都会在此刻释放 不会导致资源泄漏


以前我们在C程序里面分配的内存一定要自己释放否则就会泄漏 PHP中不需要了




2.这里有一个更绝的代码:


链接:http://hi.baidu.com/langwan/blog/item/e1e2d7c81cb446147f3e6f3a.html




for ( $i = 1; $i < 100; $i++ ) {


$str = str_repeat('01234567', $i);


$a = memory_get_usage();


unset($str);


$b = memory_get_usage();


echo "\n<br />".$i.': '.($b - $a).' Bytes.';


}




结果如下:




1: 0 Bytes.
2: 0 Bytes.
……
30: 0 Bytes.
31: 0 Bytes.
32: -272 Bytes.
33: -280 Bytes.
……
98: -800 Bytes.
99: -808 Bytes.






跟在我机器上测试的结果一样,看来unset()对占用内存多的变量作用更明显,这应该是php内部的机制,变量占用内存少的情况下,unset并不真正释放内存,因为这种占用内存小的变量(一般使用较为频繁)所导致的内存增加问题并不会太严重,只有对那些占用内存多的变量(一般使用频率低)才进行真正的内存释放。




另外,我把这个代码做了一下改动,发现很有意思的情况:




改动1:


for ( $i = 1; $i < 100; $i++ ) {


$c = memory_get_usage();


$a = memory_get_usage();


$b = memory_get_usage();


echo "\nAllocate:".$i.': '.($b - $a).' Bytes.';


echo "\n".$i.': '.($b - $a).' Bytes.';


}




输出结果:


Allocate:1: 136 Bytes.


1: 136 Bytes.


Allocate:2: 0 Bytes.


2: 0 Bytes.


Allocate:3: 0 Bytes.


3: 0 Bytes.


Allocate:4: 0 Bytes.


4: 0 Bytes.


Allocate:5: 0 Bytes.


5: 0 Bytes.


Allocate:6: 0 Bytes.


……






第一次分配的空间应该是为$a,$b,$c,$i分配的内存,以后没有内存变化




改动2:


for ( $i = 1; $i < 100; $i++ ) {


$c = memory_get_usage();


$str = str_repeat('0123456',$i);


$a = memory_get_usage();


$b = memory_get_usage();


echo "\nAllocate:".$i.': '.($a - $c).' Bytes.';


echo "\n".$i.': '.($b - $a).' Bytes.';


}




输出:


Allocate:1: 336 Bytes.


1: 136 Bytes.


Allocate:2: 0 Bytes.


2: 0 Bytes.


Allocate:3: 48 Bytes.


3: 0 Bytes.


Allocate:4: 56 Bytes.


4: 0 Bytes.


Allocate:5: 64 Bytes.


5: 0 Bytes.


Allocate:6: 0 Bytes.


6: 0 Bytes.


Allocate:7: 80 Bytes.


7: 0 Bytes.


Allocate:8: 88 Bytes.


8: 0 Bytes.


Allocate:9: 96 Bytes.


9: 0 Bytes.


Allocate:10: 104 Bytes.


10: 0 Bytes.


Allocate:11: 0 Bytes.


11: 0 Bytes.


Allocate:12: 120 Bytes.


12: 0 Bytes.


Allocate:13: 128 Bytes.


13: 0 Bytes.


Allocate:14: 136 Bytes.


14: 0 Bytes.


……


Allocate:30: 264 Bytes.


30: 0 Bytes.


Allocate:31: 272 Bytes.


31: 0 Bytes.


Allocate:32: 280 Bytes.


32: 136 Bytes.


Allocate:33: 8Bytes.


33: 0 Bytes.


Allocate:34: 8Bytes.


34: 0 Bytes.


Allocate:35: 8Bytes.


35: 0 Bytes.


……




从这里我们可以看出,从32开始是比较正常的结果,每次$str的空间增加8bytes


改动3:


for ( $i = 1; $i < 100; $i++ ) {


$c = memory_get_usage();


$str = str_repeat('0123456',$i);


$a = memory_get_usage();


unset($str);


$b = memory_get_usage();


echo "\nAllocate:".$i.': '.($a - $c).' Bytes.';


echo "\n".$i.': '.($b - $a).' Bytes.';


}




输出:


Allocate:1: 336Bytes.


1: 96 Bytes.


Allocate:2: 96Bytes.


2: 0Bytes.


Allocate:3: 48Bytes.


3: 0Bytes.


Allocate:4: 56Bytes.


4: 0 Bytes.


Allocate:5: 64Bytes.


5: 0Bytes.


Allocate:6: 0Bytes.


6: 0Bytes.


Allocate:7: 80Bytes.


7: 0Bytes.


Allocate:8: 88Bytes.


8: 0 Bytes.


Allocate:9: 96 Bytes.


9: 0 Bytes.


Allocate:10: 104 Bytes.


10: 0 Bytes.


Allocate:11: 0 Bytes.


11: 0 Bytes.


Allocate:12: 120 Bytes.


12: 0 Bytes.


Allocate:13: 128 Bytes.


13: 0 Bytes.


……


30: 0 Bytes.


Allocate:31: 272 Bytes.


31: 0 Bytes.


Allocate:32: 280Bytes.


32: -280 Bytes.


Allocate:33: 288Bytes.


33: -288Bytes.


Allocate:34:296Bytes.


34: -296Bytes.


Allocate:35: 304 Bytes.


35: -304 Bytes.


Allocate:36: 312 Bytes.


36: -312 Bytes.


……


Allocate:98: 808 Bytes.


98: -808 Bytes.


Allocate:99: 816 Bytes.


99: -816 Bytes.






3.链接:http://blog.zol.com.cn/781/article_780182.html


关于对象:


如果两个对象之间存在着相互引用的关系,如“父对象-子对象”,对父对象调用 unset() 不会释放在子对象中引用父对象的内存(即便父对象被垃圾回收,也不行)。


<?php
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
}
 
class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}
 
while (true) {
$foo = new Foo();
unset($foo);
echo number_format(memory_get_usage()) . "\n";
}
?>
 


运行这段代码,你会看到内存使用率越来越高越来越高,直到用光光。


...
33,551,616
33,551,976
33,552,336
33,552,696
PHP Fatal error: Allowed memory size of 33554432 bytes exhausted
(tried to allocate 16 bytes) in memleak.php on line 17


虽然有些乏味、不优雅,但之前提到的 bugs.php.net 链接中提供了一个解决方案。


这个方案在释放对象前使用一个 destructor 方法以达到目的。Destructor 方法可将所有内部的父对象引用全部清除,也就是说可以将这部分本来会溢出的内存释放掉。


以下是“修复后”的代码:


<?php
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
function __destruct()
{
unset($this->bar);
}
}
 
class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}
 
while (true) {
$foo = new Foo();
$foo->__destruct();
unset($foo);
echo number_format(memory_get_usage()) . "\n";
}
?>


关于unset的总结:占用小内存的变量没有必要使用unset,使用了反而会更消耗内存,当变量占用内存>256Bytes时最好调用unset;使用php OOP时,一定要自定义析构函数
原创粉丝点击