关于PHP中的unset

关于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时,一定要自定义析构函数。
原文地址:https://www.cnblogs.com/webu/p/3049913.html