PHP GC回收机制实例详解

 更新时间:2024年01月26日 09:06:29   作者:F12~  
GC的全称是Garbage Collection也就是垃圾回收的意思,在PHP中,是使用引用计数和回收周期来自动管理内存对象的,当一个对象被设置为NULL,或者没有任何指针指向时,他就会变成垃圾,被GC机制回收掉,这篇文章主要介绍了PHP GC回收机制详解 ,需要的朋友可以参考下

前言

GC的全称是Garbage Collection也就是垃圾回收的意思,在PHP中,是使用引用计数和回收周期来自动管理内存对象的,当一个对象被设置为NULL,或者没有任何指针指向时,他就会变成垃圾,被GC机制回收掉。

环境配置

php.ini终配置好xdebug,xdebug_debug_zval是用来查看容器变量内容的函数

<?php 
$a = "F12";
xdebug_debug_zval("a");
?>

在PHP GC机制中,当程序终止时就会让变量的refcount减1,如果refcount-1为0的话,就会销毁回收该变量

引用计数

is_ref表示该变量是否被引用,操作系统学的好的同学应该很容易理解该内容

<?php 
  $a = "F12";
  $b = &$a;
  xdebug_debug_zval("a");
?>
# 运行结果
a: (refcount=2, is_ref=1)='F12'

$b是$a的引用,所以is_ref=1,同时refcount也会加1,因为此时是有两个变量的(两变量指向同一个地址),所以销毁时要让refcount减2。
当变量是array类型时,也是一样的规则

<?php 
  $a = "F12";
  $arr = array(0=>"test", 1=>&$a);
  xdebug_debug_zval("arr");
?>
# 运行结果
arr: (refcount=1, is_ref=0)=array (0 => (refcount=1, is_ref=0)='test', 1 => (refcount=2, is_ref=1)='F12')

如果我们在引用前将$a销毁会发生什么?

<?php 
  $a = "F12";
  unset($a);
  $arr = array(0=>"test", 1=>&$a);
  xdebug_debug_zval("a");
  xdebug_debug_zval("arr");
?>
# 运行结果
a: (refcount=2, is_ref=1)=NULL
arr: (refcount=1, is_ref=0)=array (0 => (refcount=1, is_ref=0)='test', 1 => (refcount=2, is_ref=1)=NULL)
<?php 
  $a = "F12";
  $arr = array(0=>"test", 1=>&$a);
  unset($a);
  xdebug_debug_zval("a");
  xdebug_debug_zval("arr");
?>
# 运行结果
a: no such symbol
arr: (refcount=1, is_ref=0)=array (0 => (refcount=1, is_ref=0)='test', 1 => (refcount=1, is_ref=1)='F12')

第一种情况,$a没有被销毁,因为在之后又引用了$a,所以$a只是指向了一个NULL,第二种情况就把$a销毁了

PHP GC在反序列化中的使用

一个简单的demo

<?php
class gc{
    public $num;
    public function __construct($num)
    {
        $this->num=$num;
        echo "construct(".$num.")"."\n";
    }
    public function __destruct()
    {
        echo "destruct(".$this->num.")"."\n";
    }
}
$a=new gc(1);
$b=new gc(2);
$c=new gc(3);
# 运行结果
construct(1)
construct(2)
construct(3)
destruct(3)
destruct(2)
destruct(1)

先创建的对象最后销毁,看看变量的内容情况:

可以看到refcount为1,所以当程序结束时,减1就会被回收
如果我们不把new的gc对象赋值给$a会怎样?

<?php
class gc{
    public $num;
    public function __construct($num)
    {
        $this->num=$num;
        echo "construct(".$num.")"."\n";
    }
    public function __destruct()
    {
        echo "destruct(".$this->num.")"."\n";
    }
}
new gc(1);
$b=new gc(2);
$c=new gc(3);
# 运行结果
construct(1)
destruct(1)
construct(2)
construct(3)
destruct(3)
destruct(2)

可以看到第一个gc对象,创建完就被回收了,因为没被其它变量引用,它的refcount一开始就是0,所以直接被回收

绕过Exception异常

思路一

一个简单的demo:

<?php
class gc{
    public $num;
    public function __construct($num)
    {
        $this->num=$num;
    }
    public function __destruct()
    {
        echo "Hello World!";
    }
}
$a = new gc(1);
$ser = serialize($a);
$b = unserialize($ser);
throw new Exception("F12 is bad");

正常来说会输出一个Hello World!,但是因为触发了异常,所以对象并没有被回收

我们修改一下代码:

<?php
class gc{
    public $num;
    public function __construct($num)
    {
        $this->num=$num;
    }
    public function __destruct()
    {
        echo "Hello World!";
    }
}
$a = array(0=>new gc(1),1=>1);
$ser = serialize($a);
echo $ser;
$ser = 'a:2:{i:0;O:2:"gc":1:{s:3:"num";i:1;}i:0;i:1;}';
$b = unserialize($ser);
throw new Exception("F12 is bad");

这里我们我们修改序列化的内容,将$a[0]随便指向谁,从而使new的gc对象没有引用的变量,所以触发提前回收,跟上面举的直接new gc,并不赋值是一个道理

思路二

这种方法更加简单粗暴,我们只需要让序列化的数据出错,那么当反序列化时出错时,也会让该对象提前回收

<?php
class gc{
    public $num;
    public function __construct($num)
    {
        $this->num=$num;
    }
    public function __destruct()
    {
        echo "Hello World!";
    }
}
$a = new gc(1);
$ser = serialize($a);
echo $ser;
$ser = 'O:2:"gc":1:{s:3:"num";i:1;';
$b = unserialize($ser);
throw new Exception("F12 is bad");

这里我们删去一个},依然输出了Hello World!

到此这篇关于PHP GC回收机制详解 的文章就介绍到这了,更多相关PHP GC回收机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • PHP开发api接口安全验证的实例讲解

    PHP开发api接口安全验证的实例讲解

    下面小编就为大家分享一篇PHP开发api接口安全验证的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03
  • PHP调用wsdl文件类型的接口代码分享

    PHP调用wsdl文件类型的接口代码分享

    本文给大家分享了一个PHP调用wsdl文件类型的接口代码,非常的简单也很实用,有相关需求的小伙伴们可以直接拿去用的。
    2014-11-11
  • PHP验证终端类型是否为手机的简单实例

    PHP验证终端类型是否为手机的简单实例

    下面小编就为大家带来一篇PHP验证终端类型是否为手机的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • 微信公众号判断用户是否已关注php代码解析

    微信公众号判断用户是否已关注php代码解析

    这篇文章主要大家详细解析了微信公众号判断用户是否已关注php代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Thinkphp自定义代码生成工具及用法说明(附下载地址)

    Thinkphp自定义代码生成工具及用法说明(附下载地址)

    这篇文章主要介绍了Thinkphp自定义代码生成工具及用法说明,简单分析了自定义代码生成工具的作用及用法,并附带了下载地址,需要的朋友可以参考下
    2016-05-05
  • Laravel 5.5基于内置的Auth模块实现前后台登陆详解

    Laravel 5.5基于内置的Auth模块实现前后台登陆详解

    最近在使用laravel5.5,利用其实现了一个功能,下面分享给大家,这篇文章主要给大家介绍了关于Laravel 5.5基于内置的Auth模块如何实现前后台登陆的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-12-12
  • PHP基于yii框架实现生成ICO图标

    PHP基于yii框架实现生成ICO图标

    本文给大家分享了2则php生成ICO图标的代码,第一款是基于YII框架实现的,第二款是纯php编写,都非常的不错,有需要的小伙伴可以参考下
    2015-11-11
  • ThinkPHP中自定义错误页面和提示页面实例

    ThinkPHP中自定义错误页面和提示页面实例

    这篇文章主要介绍了ThinkPHP中自定义错误页面和提示页面的方法,以一个完整的实例形式详细讲述了ThinkPHP实现自定义错误提示与跳转页面的方法,是非常常见的实用技巧,需要的朋友可以参考下
    2014-11-11
  • thinkPHP的表达式查询用法详解

    thinkPHP的表达式查询用法详解

    这篇文章主要介绍了thinkPHP的表达式查询用法,结合实例形式分析了thinkPHP表达式查询的格式及相关运算符用法,需要的朋友可以参考下
    2016-09-09
  • PHP、Java des加密解密实例

    PHP、Java des加密解密实例

    这篇文章主要介绍了PHP、Java des加密解密实例,des加密是对称加密中在互联网应用的比较多的一种加密方式,本文分别给出了PHP和JAVA版本的实现代码,需要的朋友可以参考下
    2015-04-04

最新评论