翼度科技»论坛 编程开发 PHP 查看内容

PHP GC回收机制实例详解

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
前言

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

环境配置

php.ini终配置好xdebug,
  1. xdebug_debug_zval
复制代码
是用来查看容器变量内容的函数
  1. <?php
  2. $a = "F12";
  3. xdebug_debug_zval("a");
  4. ?>
复制代码

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

引用计数
  1. is_ref
复制代码
表示该变量是否被引用,操作系统学的好的同学应该很容易理解该内容
  1. <?php
  2.   $a = "F12";
  3.   $b = &$a;
  4.   xdebug_debug_zval("a");
  5. ?>
  6. # 运行结果
  7. a: (refcount=2, is_ref=1)='F12'
复制代码
$b是$a的引用,所以
  1. is_ref=1
复制代码
,同时
  1. refcount
复制代码
也会加1,因为此时是有两个变量的(两变量指向同一个地址),所以销毁时要让
  1. refcount
复制代码
减2。
当变量是array类型时,也是一样的规则
  1. <?php
  2.   $a = "F12";
  3.   $arr = array(0=>"test", 1=>&$a);
  4.   xdebug_debug_zval("arr");
  5. ?>
  6. # 运行结果
  7. arr: (refcount=1, is_ref=0)=array (0 => (refcount=1, is_ref=0)='test', 1 => (refcount=2, is_ref=1)='F12')
复制代码
如果我们在引用前将$a销毁会发生什么?
  1. <?php
  2.   $a = "F12";
  3.   unset($a);
  4.   $arr = array(0=>"test", 1=>&$a);
  5.   xdebug_debug_zval("a");
  6.   xdebug_debug_zval("arr");
  7. ?>
  8. # 运行结果
  9. a: (refcount=2, is_ref=1)=NULL
  10. arr: (refcount=1, is_ref=0)=array (0 => (refcount=1, is_ref=0)='test', 1 => (refcount=2, is_ref=1)=NULL)
复制代码
  1. <?php
  2.   $a = "F12";
  3.   $arr = array(0=>"test", 1=>&$a);
  4.   unset($a);
  5.   xdebug_debug_zval("a");
  6.   xdebug_debug_zval("arr");
  7. ?>
  8. # 运行结果
  9. a: no such symbol
  10. 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
  1. <?php
  2. class gc{
  3.     public $num;
  4.     public function __construct($num)
  5.     {
  6.         $this->num=$num;
  7.         echo "construct(".$num.")"."\n";
  8.     }
  9.     public function __destruct()
  10.     {
  11.         echo "destruct(".$this->num.")"."\n";
  12.     }
  13. }
  14. $a=new gc(1);
  15. $b=new gc(2);
  16. $c=new gc(3);
  17. # 运行结果
  18. construct(1)
  19. construct(2)
  20. construct(3)
  21. destruct(3)
  22. destruct(2)
  23. destruct(1)
复制代码
先创建的对象最后销毁,看看变量的内容情况:

可以看到
  1. refcount
复制代码
为1,所以当程序结束时,减1就会被回收
如果我们不把new的gc对象赋值给$a会怎样?
  1. <?php
  2. class gc{
  3.     public $num;
  4.     public function __construct($num)
  5.     {
  6.         $this->num=$num;
  7.         echo "construct(".$num.")"."\n";
  8.     }
  9.     public function __destruct()
  10.     {
  11.         echo "destruct(".$this->num.")"."\n";
  12.     }
  13. }
  14. new gc(1);
  15. $b=new gc(2);
  16. $c=new gc(3);
  17. # 运行结果
  18. construct(1)
  19. destruct(1)
  20. construct(2)
  21. construct(3)
  22. destruct(3)
  23. destruct(2)
复制代码
可以看到第一个gc对象,创建完就被回收了,因为没被其它变量引用,它的
  1. refcount
复制代码
一开始就是0,所以直接被回收

绕过Exception异常


思路一

一个简单的demo:
  1. <?php
  2. class gc{
  3.     public $num;
  4.     public function __construct($num)
  5.     {
  6.         $this->num=$num;
  7.     }
  8.     public function __destruct()
  9.     {
  10.         echo "Hello World!";
  11.     }
  12. }
  13. $a = new gc(1);
  14. $ser = serialize($a);
  15. $b = unserialize($ser);
  16. throw new Exception("F12 is bad");
复制代码
正常来说会输出一个
  1. Hello World!
复制代码
,但是因为触发了异常,所以对象并没有被回收

我们修改一下代码:
  1. <?php
  2. class gc{
  3.     public $num;
  4.     public function __construct($num)
  5.     {
  6.         $this->num=$num;
  7.     }
  8.     public function __destruct()
  9.     {
  10.         echo "Hello World!";
  11.     }
  12. }
  13. $a = array(0=>new gc(1),1=>1);
  14. $ser = serialize($a);
  15. echo $ser;
  16. $ser = 'a:2:{i:0;O:2:"gc":1:{s:3:"num";i:1;}i:0;i:1;}';
  17. $b = unserialize($ser);
  18. throw new Exception("F12 is bad");
复制代码
这里我们我们修改序列化的内容,将$a[0]随便指向谁,从而使new的gc对象没有引用的变量,所以触发提前回收,跟上面举的直接new gc,并不赋值是一个道理


思路二

这种方法更加简单粗暴,我们只需要让序列化的数据出错,那么当反序列化时出错时,也会让该对象提前回收
  1. <?php
  2. class gc{
  3.     public $num;
  4.     public function __construct($num)
  5.     {
  6.         $this->num=$num;
  7.     }
  8.     public function __destruct()
  9.     {
  10.         echo "Hello World!";
  11.     }
  12. }
  13. $a = new gc(1);
  14. $ser = serialize($a);
  15. echo $ser;
  16. $ser = 'O:2:"gc":1:{s:3:"num";i:1;';
  17. $b = unserialize($ser);
  18. throw new Exception("F12 is bad");
复制代码
这里我们删去一个
  1. }
复制代码
,依然输出了
  1. Hello World!
复制代码

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

来源:https://www.jb51.net/program/314191ceh.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具