php的垃圾回收机制

PHP的垃圾回收机制主要有两部分组成:引用计数方法和循环引用收集器。

引用计数方法

1、php把每个变量都存在一个叫"zval"的变量容器中。zval变量容器,不仅包含变量的类型和值,还两个字节的额外信息"is_ref"和"refcount"。

  • "is_ref",是个bool值,用来标识这个变量是否是属于引用集合(reference set)。通过这个值,PHP 引擎知道如何区分普通变量和引用。由于 PHP 允许用户自定义引用,通过 & 运算符创建引用,zval 容器还有内部引用计数机制来优化内存使用。
  • "refcount",用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。

2、"refcount"的计数规则,定义变量是"refcount" 默认为1,当变量被赋值给另一个变量时"refcount" 加1。当使用unset()删除变量时"refcount" 减1,当任何关联到某个变量容器的变量离开它的作用域(比如:函数执行结束)"refcount" 减1。

3、变量容器在”refcount“变成0时就被销毁。

循环引用收集器

虽然引用计数方法很实用,但是在处理如下情况时会失效:如果你创建了两个对象,并让它们相互引用,即使你将原始的引用全部消除,它们的"refcount"也永远不会降至0(因为它们彼此间一直在引用对方),从而导致内存泄露。例如:

$a = new stdClass();
$b = new stdClass();

$a->child = $b;
$b->parent = $a;

此时,即使 $a$b 两个变量被 unset,他们指向的对象也不会被销毁,因为它们彼此持有对方的引用,造成了循环引用,引用计数永远不会降到0。

为了解决循环引用的问题,PHP的Zend引擎实现了循环引用收集器。这个机制不会替代传统的引用计数模型,而是作为补充来处理特定情况下的内存泄漏。

当更改变量内容(如赋值、unset等)时,如果变量容器的引用计数不为0,但是达到了可以释放的条件,Zend引擎会将这些容器放入一个特殊的缓冲区中。这个缓冲区不会立即处理,而是在以下任一条件满足时触发垃圾收集周期:

  • 缓冲区达到一定大小(可以通过 gc_collect_cycles() 手动触发)。
  • 程序终止期间。

垃圾收集周期工作流程如下:

  1. 标记根缓冲区:检查放在缓冲区内的所有变量容器,如果它们的引用计数为1(只有因为循环引用而没有被销毁),则认为它们是“可能的”根节点。
  2. 构建根缓冲区:对每个可能的根节点进行遍历,寻找循环引用结构。
  3. 清理:清除检测到的循环引用,并释放相关资源。
     

打开和关闭垃圾回收机制的循环引用收集器

​可以在php.ini中的zend.enable_gc开启垃圾回收机制的循环引用收集器,也能通过分别调用gc_enable() 和 gc_disable()函数来打开和关闭垃圾回收机制的循环引用收集器。

在PHP编程中,关于垃圾回收机制优化代码,可以遵循以下几点注意事项:

  1. 尽量避免创建大量的长生命周期的对象,如果必要,当不再需要这些对象时,尽可能显式地销毁他们(例如:使用unset()函数)。

  2. 对于大量的临时数据,试图将其放在函数的局部变量中,并确保它们在函数返回后被清除。

  3. 避免使用全局变量来存储大量的数据。全局变量通常会在整个脚本执行期间存在,从而增加了内存使用。

  4. 尽量避免创建循环引用。即使你有一个完美的理由去这么做,也请确保在不再需要这些对象时解除引用。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值