关于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时,一定要自定义析构函数
关于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时,一定要自定义析构函数