使用脚本语言最大
![](/icons/87800de.gif)
好处的
![](/icons/87800yi.gif)
就是可利用其拥有
![](/icons/87800de.gif)
自动垃圾回收机制(释放内存)
![](/icons/87800dou2.gif)
你不需要在使用完变量后做任何释放内存
![](/icons/87800de.gif)
处理
![](/icons/87800dou.gif)
PHP会帮你完成
![](/icons/87800dou2.gif)
当然
![](/icons/87800dou.gif)
我们可以按自己
![](/icons/87800de.gif)
意愿
![](/icons/87800diaoyong.gif)
un
![](/icons/87800set.gif)
![](/icons/87800hanshu.gif)
来释放内存
![](/icons/87800dou.gif)
但通常不需要这么做
![](/icons/87800dou2.gif)
不过在PHP里
![](/icons/87800dou.gif)
至少有
![](/icons/87800yi.gif)
种情况内存不会得到自动释放
![](/icons/87800dou.gif)
即便是手动
![](/icons/87800diaoyong.gif)
un
![](/icons/87800set.gif)
![](/icons/87800kh.gif)
![](/icons/87800dou2.gif)
详情可考:http://bugs.php.net/bug.php?id=33595
![](/icons/87800dou2.gif)
问题症状
如果两个对象的间存在着相互引用
![](/icons/87800de.gif)
关系
![](/icons/87800dou.gif)
如“父对象-子对象”
![](/icons/87800dou.gif)
对父对象
![](/icons/87800diaoyong.gif)
un
![](/icons/87800set.gif)
![](/icons/87800kh.gif)
不会释放在子对象中引用父对象
![](/icons/87800de.gif)
内存(即便父对象被垃圾回收
![](/icons/87800dou.gif)
也不行)
![](/icons/87800dou2.gif)
有些糊涂了?我们来看下面
![](/icons/87800de.gif)
这段代码:
<?php
![](/icons/87800class.gif)
Foo {function __construct
![](/icons/87800kh.gif)
{$this->bar =
![](/icons/87800new.gif)
Bar($this);}}
![](/icons/87800class.gif)
Bar {function __construct($foo = null){$this->foo = $foo;}}while (true) {$foo =
![](/icons/87800new.gif)
Foo
![](/icons/87800kh.gif)
;un
![](/icons/87800set.gif)
($foo);echo number_format(memory_get_usage
![](/icons/87800kh.gif)
) . "n";}?>运行这段代码
![](/icons/87800dou.gif)
你会看到内存使用率越来越高越来越高
![](/icons/87800dou.gif)
直到用光光
![](/icons/87800dou2.gif)
...33,551,61633,551,97633,552,33633,552,696PHP Fatal error: Allowed memory size of 33554432
![](/icons/87800byte.gif)
s exhausted(tried to allocate 16
![](/icons/87800byte.gif)
s) in memleak.php _disibledevent=
![](/icons/87800new.gif)
Foo
![](/icons/87800kh.gif)
;$foo->__destruct
![](/icons/87800kh.gif)
;un
![](/icons/87800set.gif)
($foo);echo number_format(memory_get_usage
![](/icons/87800kh.gif)
) . "n";}?>注意那个新增
![](/icons/87800de.gif)
Foo::__destruct
![](/icons/87800kh.gif)
思路方法
![](/icons/87800dou.gif)
以及在释放对象前对 $foo->__destruct
![](/icons/87800de.gif)
![](/icons/87800diaoyong.gif)
![](/icons/87800dou2.gif)
现在这段代码解决了内存使用率
![](/icons/87800yi.gif)
直增加
![](/icons/87800de.gif)
问题
![](/icons/87800dou.gif)
这么
![](/icons/87800yi.gif)
来,代码就可以很好
![](/icons/87800de.gif)
工作了
![](/icons/87800dou2.gif)
PHP内核解决方案?
为什么会有内存溢出
![](/icons/87800de.gif)
发生?我对PHP内核方面
![](/icons/87800de.gif)
研究并不精通
![](/icons/87800dou.gif)
但可以确定
![](/icons/87800de.gif)
是此问题和引用计数有关系
![](/icons/87800dou2.gif)
在 $bar 中引用 $foo
![](/icons/87800de.gif)
引用计数不会
![](/icons/87800yinwei.gif)
父对象 $foo 被释放而递减
![](/icons/87800dou.gif)
这时PHP认为你仍需要 $foo 对象
![](/icons/87800dou.gif)
也就不会释放这部分
![](/icons/87800de.gif)
内存……大概是这样
![](/icons/87800dou2.gif)
这里确实可以看出我
![](/icons/87800de.gif)
无知
![](/icons/87800dou.gif)
但大体意思是:
![](/icons/87800yi.gif)
个引用计数没有递减
![](/icons/87800dou.gif)
所以
![](/icons/87800yi.gif)
些内存永远得不到释放
![](/icons/87800dou2.gif)
在前面提到
![](/icons/87800de.gif)
bugs.php.net 链接中我看到修改垃圾回收
![](/icons/87800de.gif)
过程将会牺牲极大
![](/icons/87800de.gif)
性能
![](/icons/87800dou.gif)
![](/icons/87800yinwei.gif)
我对引用计数了解不多
![](/icons/87800dou.gif)
所以我认为这是真
![](/icons/87800de.gif)
![](/icons/87800dou2.gif)
和其改变垃圾回收
![](/icons/87800de.gif)
过程
![](/icons/87800dou.gif)
为什么不用 un
![](/icons/87800set.gif)
![](/icons/87800kh.gif)
对内部对象做释放
![](/icons/87800de.gif)
工作呢?(或者在释放对象
![](/icons/87800de.gif)
时候
![](/icons/87800diaoyong.gif)
__destruct
![](/icons/87800kh.gif)
?)
也许PHP内核开发者可以在此或其他地方
![](/icons/87800dou.gif)
对这种垃圾回收处理机制做出修改
![](/icons/87800dou2.gif)
更新:Martin Fjordvald 在评论中提到了
![](/icons/87800yi.gif)
个由 David Wang 为垃圾回收所写
![](/icons/87800de.gif)
补丁(其实它看起来更像“
![](/icons/87800yi.gif)
整块布”——非常巨大
![](/icons/87800dou2.gif)
详情参见此邮件结尾
![](/icons/87800de.gif)
CVS导出信息
![](/icons/87800dou2.gif)
)确实存在(
![](/icons/87800yi.gif)
封邮件)
![](/icons/87800dou.gif)
并受到了PHP内核开发成员
![](/icons/87800de.gif)
关注
![](/icons/87800dou2.gif)
问题是这个补丁要不要放到PHP5.3中并未得到太多支持
![](/icons/87800dou2.gif)
我觉得
![](/icons/87800yi.gif)
个不错
![](/icons/87800de.gif)
折中方案就是在 un
![](/icons/87800set.gif)
![](/icons/87800hanshu.gif)
中
![](/icons/87800diaoyong.gif)
对象中
![](/icons/87800de.gif)
__destruct
![](/icons/87800kh.gif)
思路方法;