京东6.18大促主会场领京享红包更优惠

 找回密码
 立即注册

QQ登录

只需一步,快速开始

PHP GC回收机制实例详解

2024-11-3 20:00| 发布者: 284cc| 查看: 114| 评论: 0

摘要: 目次媒介环境设置引用计数PHP GC在反序列化中的使用绕过Exception异常思路一思路二媒介 GC的全称是Garbage Collection也就是垃圾回收的意思,在PHP中,是使用引用计数和回收周期来自动管理内存对象的,当一个对象被
目次

媒介

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

环境设置

php.ini终设置好xdebug,[code]xdebug_debug_zval[/code]是用来查察容器变量内容的函数

[code]<?php $a = "F12"; xdebug_debug_zval("a"); ?>[/code]

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

引用计数

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

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

$b是$a的引用,以是[code]is_ref=1[/code],同时[code]refcount[/code]也会加1,由于此时是有两个变量的(两变量指向同一个地址),以是销毁时要让[code]refcount[/code]减2。
当变量是array范例时,也是一样的规则

[code]<?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')[/code]

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

[code]<?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)[/code] [code]<?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')[/code]

第一种环境,$a没有被销毁,由于在之后又引用了$a,以是$a只是指向了一个NULL,第二种环境就把$a销毁了

PHP GC在反序列化中的使用

一个简朴的demo

[code]<?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)[/code]

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

可以看到[code]refcount[/code]为1,以是当程序竣事时,减1就会被回收
假如我们不把new的gc对象赋值给$a会怎样?

[code]<?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)[/code]

可以看到第一个gc对象,创建完就被回收了,由于没被别的变量引用,它的[code]refcount[/code]一开始就是0,以是直接被回收

绕过Exception异常

思路一

一个简朴的demo:

[code]<?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");[/code]

正常来说会输出一个[code]Hello World![/code],但是由于触发了异常,以是对象并没有被回收

我们修改一下代码:

[code]<?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");[/code]

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

思路二

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

[code]<?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");[/code]

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

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


来源:https://www.jb51.net/program/314191ceh.htm
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
关闭

站长推荐上一条 /6 下一条

QQ|手机版|小黑屋|梦想之都-俊月星空 ( 粤ICP备18056059号 )|网站地图

GMT+8, 2025-7-1 21:52 , Processed in 0.031697 second(s), 18 queries .

Powered by Mxzdjyxk! X3.5

© 2001-2025 Discuz! Team.

返回顶部