• 售前

  • 售后

热门帖子
入门百科

PHP垃圾接纳机制讲授

[复制链接]
李志敏 显示全部楼层 发表于 2021-8-14 15:01:12 |阅读模式 打印 上一主题 下一主题
PHP的垃圾接纳机制

垃圾接纳机制是一种动态存储分配的方案。它会主动释放程序不再需要的已分配的内存块。垃圾接纳机制可以让程序员不必太过关心程序内存分配,从而将更多的精力投入到业务逻辑。在现在的流行各种语言当中,垃圾接纳机制是新一代语言所共有的特征,如Python、PHP、C#、Ruby等都利用了垃圾接纳机制。
好了,进入代码实战阶段,注意两点:
  1. $a = 'hello'. mt_rand( 1, 1000 );
  2. echo xdebug_debug_zval( 'a');
  3. $b = $a;
  4. echo xdebug_debug_zval( 'a');
  5. $c = $a;
  6. echo xdebug_debug_zval( 'a');
  7. unset( $c );
  8. echo xdebug_debug_zval( 'a');
复制代码
输出的结果是:

此中,zval struct布局体用于生存$a,zend_value union联合体用于生存数据内容也就是'hello916'。由于反面又声明确b和c,以是C不得不又在底层给你搞出两个zval struct布局体来。
此中,zval和zend value的布局大概如下:(注意!!!这并不是完整准确的PHP zval和zend_value在C语言中struct和union实现,仅仅是挑出最重点的部门写出来,强调一下:你没有须要一个字不差背诵过zval和zend_value,你只需要知道原理)
zval {
string "a" //变量的名字是a
value zend_value //变量的值
type string //变量是字符串范例
}
zend_value {
string "hello916" //值的内容
refcount 1 //引用计数
}
看到上面两个,如果面试官问你php变量为什么能够生存字符串"123"也能生存数字123,你知道该怎么回答了吧?就答出重点zval中有该变量的范例,当是字符串123的时候,type就是string,此时value指向“123”;当是整数123的时候,zval的type为int,value为123。这就是答题的头脑,这很重要!而且,通过C语言都是可以实现的!具体真正的val和zend_value的容貌,有爱好的同砚可以去网上搜搜,如果你没有C语言的根本,大概比力吃力!前者是一个struct布局体,后者是一个union联合体!
这个refcount就是传说中的引用计数了,初始化的时候a反面的引用次数为1(注意,准确说法应该是a反面的赋值的数组zend_value引用计数为1,而不是a这个变量zval自己)。然后我们将$b = $a,其实相当于又一个变量指向了这个zend_value,以是refcount变为2,最后将$c = $a,同理,zend_value的refcount再次加1酿成了3。然后,我们用unset( $c ),这会儿,C语言要做的就是把$c的zval给KO free掉,但是并不是free zend_value,这会儿zend_value的refcount就天然而然减1酿成2了。
那么写时拷贝是什么意思呢?看下面代码:
  1. <?php
  2. // 先不要问为什么非要加mt_rand,不然,绝笔说不过来了,到处都是坑
  3. $a = 'hello'. mt_rand( 1, 1000 );
  4. $b = $a;
  5. $a = 123;
  6. echo $b. PHP_EOL;
  7. // 运行结果,不用我说吧,脚趾头都知道是'hello'.mt_rand( 1, 1000 )的结果,绝对不可能是123。
复制代码
其实,当你把$a赋值给$b的时候,$a的值并没有真的复制了一份,这样是对内存的非常不尊重,也是对时间复杂度的非常不尊重,盘算机仅仅是将$b指向了$a的值而已,这就叫多快好省。那么,什么时候真正的发生复制呢?就是当我们修改$a的值为123的时候,这个时候就不得已进行复制,制止$b的值和$a的一样。
  1. <?php
  2. $a = 'hello'. mt_rand( 1, 1000 );
  3. $b = $a;
  4. echo xdebug_debug_zval( 'a');
  5. $a = 'world'. mt_rand( 2, 2000 );
  6. echo xdebug_debug_zval( 'a');
  7. // 运行结果为1,其中的原理你自己应该能理顺了昂
复制代码
叨逼叨了这么长,通过简单的案例表明清晰了两个要点:引用计数和写时拷贝,那么垃圾接纳也该来了。当一个zval在被unset的时候、大概从一个函数中运行完毕出来(就是局部变量)的时候等等许多地方,都会产生zval与zend_value发生断开的行为,这个时候zend引擎需要检测的就是zend_value的refcount是否为0,如果为0,则直接KO free空出内容来。如果zend_value的recount不为0(废话一定是大于0),这个value不能被释放,但是也不代表这个zend_value是明净的,由于此zend_value依然大概是个垃圾。
什么样的环境会导致zend_value的refcount不为0,但是这个zend_value却是个垃圾呢?PHP7种两种环境:
  1. <?php
  2. $arr = [ 1 ];
  3. $arr[] = &$arr;
  4. unset( $arr );
复制代码
这种环境下,zend_value不会能释放,但也不能放过它,不然一定会产生内存走漏,以是这会儿zend_value会被扔到一个叫做垃圾接纳堆中,然后zend引擎会依次对垃圾接纳堆中的这些zend_value进行二次检测,检测是不是由于上述两种环境造成的refcount为1但是自身却确实没有人再用了,如果一旦确定是上述两种环境造成的,那么就会将zend_value彻底抹掉释放内存。
那么垃圾接纳发生在什么时候?有些同砚大概有疑问,就是php不是运行一次就烧毁了吗,我要着gc有何用?并不是啦,首先当一次fpm运行完毕后,最后一定另有gc的,这个烧毁就是gc;其次是,内存都是即用即释放的,而不是攒着非得到最后,你想想一个典范的场景,你的控制器里的某个方法里用了一个函数,函数需要一个巨大的数组参数,然后函数还需要修改这个巨大的数组参数,你们应该是函数的运行范围里面修改这个数组,以是此时会发生写时拷贝了,当函数运行完毕后,就得赶紧释放掉这块儿内存以供给其他历程利用,而不好坏得等到本地fpm request彻底完成后才烧毁。
说到最后,说些自己的话:大多数环境下,面试官问你问题重要是想一是要你个头脑思绪,二是看你学习水平。就像gc这个问题,其实许多脚本语言的垃圾接纳机制根本上都是靠引用计数和写时拷贝这两种算法结合完成的,以是如果你筹划一门脚本语言,gc机制就按照这两种算法进行筹划即可。其次是大多数phper不会看这些东西的,面试官问你这个问题不是要你死记硬背那么多细节,你背不外的,他还是想探测你平常有没有更积极地往深层发展的心态。
注意体现重点,许多细节着实没法写,比如我举个例子$a=[],xdebug_debug_zval( $a )的refcount值你猜是多少? 7.1.17下竟然是2,你是不是以为是1,然而并不是。不外你不用纠结这些细节,gc的关键就是能说出引用计数的原理和写时拷贝,许多细节深处都各种奇奇怪怪的东西,面试官自己都不一定知道。
到此这篇关于PHP垃圾接纳机制讲解的文章就介绍到这了,更多干系PHP垃圾接纳机制内容请搜索草根技术分享从前的文章或继承欣赏下面的干系文章希望各人以后多多支持草根技术分享!

本帖子中包含更多资源

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

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作