PHP7垃圾回收机制怎样的呢,与C语言有何不同
Admin 2022-08-20 群英技术资讯 525 次浏览
垃圾回收:
简称GC。顾名思义,就是废物重利用的意思。
说垃圾回收机制之前,先接触一下内存泄漏。
内存泄漏:
某大神重口味充满画面感的形象解释:
大概意思就是申请了一块地儿拉了会儿屎,拉完后不收拾,那么那块儿地就算是糟蹋了,地越用越少,最后一地全是屎。说到底一句,用了记得还。一定程度上说,垃圾回收机制就是用来擦屁股的。
c语言垃圾回收机制:
如果用过C语言,那么申请内存的方式是malloc或者是calloc,然后你用完这个内存后,一定不要忘了用free函数去释放掉,这就是手动垃圾回收,一般都是大神用这种方式。
php的自动垃圾回收机制是怎样的呢?
这个问题我们先这么想,我们都知道php是C语言实现的。你想想如何用C语言实现对一个变量的统计以及释放。C语言是如何实现一个变量,从声明开始到最后没人用了,就把这个变量所占的内存给释放掉(被垃圾回收)。
PHP进行内存管理的核心算法一共两项:
一是引用计数,二是写时拷贝
声明一个PHP变量的时候,C语言就在底层生成一个叫做zval的struct(结构体),如下:
zval { string "a" //变量的名字是a value zend_value //变量的值,联合体 type string //变量是字符串类型 }
zval struct结构体
(1)保存php $a的变量名
(2)php $a的变量类型
(3)php变量$a的zend_value联合体
如果给变量赋值了,比如“hello world”,那么C语言就在底层再生成一个叫做zend_value的union(联合体)
zend_value { string "hello world" //值的内容 refcount 1 //引用计数 }
zend_value的union(联合体)
(1)保存php $a的变量的值hello world
(2)记录php $a变量引用次数
看到 zval struct结构体和zend_value,如果面试官问你php变量为什么能够保存字符串"123"也能保存数字123,你知道该怎么回答了吧?就答出重点zval中有该变量的类型,当是字符串123的时候,type就是string,此时value指向“123”;当是整数123的时候,zval的type为int,value为123。
何为引用计数?
代码实战解析php变量引用计数
$a = 'hello,world'; echo xdebug_debug_zval( 'a');//refcount=1 $b = $a; echo xdebug_debug_zval( 'a'); //$b引用$a,故变量a,refcount=2 $c = $a; echo xdebug_debug_zval( 'a'); //$c引用$a,故变量a,refcount=3 unset( $c ); echo xdebug_debug_zval( 'a');//删除了$c的引用,故变量a,refcount=2
运行结果:
a:
(refcount=1, is_ref=0)string 'hello,world' (length=11)
a:
(refcount=2, is_ref=0)string 'hello,world' (length=11)
a:
(refcount=3, is_ref=0)string 'hello,world' (length=11)
a:
(refcount=2, is_ref=0)string 'hello,world' (length=11)
何为拷贝复制?
$a = 'hello'; $b = $a;//$a赋值给$b的时候,$a的值并没有真的复制了一份 echo xdebug_debug_zval( 'a');//$a的引用计数为2 $a = 'world';//当我们修改$a的值为123的时候,这个时候就不得已进行复制,避免$b的值和$a的一样 echo xdebug_debug_zval( 'a');///$a的引用计数为1
运行结果:
a:
(refcount=2, is_ref=0)string 'hello' (length=5)
a:
(refcount=1, is_ref=0)string 'world' (length=5)
其实,当你把$a赋值给$b的时候,$a的值并没有真的复制了一份,这样是对内存的极度不尊重,也是对时间复杂度的极度不尊重,计算机仅仅是将$b指向了$a的值而已,这就叫多快好省。那么,什么时候真正的发生复制呢?就是当我们修改$a的值为123的时候,这个时候就不得已进行复制,避免$b的值和$a的一样。
通过简单的案例解释清楚了两个要点:引用计数和写时拷贝。
垃圾回收机制:
当一个zval在被unset的时候、或者从一个函数中运行完毕出来(就是局部变量)的时候等等很多地方,都会产生zval与zend_value发生断开的行为,这个时候zend引擎需要检测的就是zend_value的refcount是否为0,如果为0,则直接KO free空出内容来。如果zend_value的recount不为0,这个value不能被释放,但是也不代表这个zend_value是清白的,因为此zend_value依然可能是个垃圾。
(1)当php变量$a的refcount=0时,变量$a就会被垃圾回收
(2)当php变量$a的refcount>0时,变量$a但也可能被认为是垃圾
什么样的情况会导致zend_value的refcount不为0,但是这个zend_value却是个垃圾呢?
$arr = [ 1 ]; $arr[] = &$arr; unset( $arr );
这种情况下,zend_value不会能释放,但也不能放过它,不然一定会产生内存泄漏,所以这会儿zend_value会被扔到一个叫做垃圾回收堆中,然后zend引擎会依次对垃圾回收堆中的这些zend_value进行二次检测,检测是不是由于上述两种情况造成的refcount为1但是自身却确实没有人再用了,如果一旦确定是上述两种情况造成的,那么就会将zend_value彻底抹掉释放内存。
垃圾回收发生在什么时候?
有些同学可能有疑问,就是php不是运行一次就销毁了吗,我要gc有何用?并不是的,首先当一次fpm运行完毕后,最后一定还有gc的,这个销毁就是gc;其次是,内存都是即用即释放的,而不是攒着非得到最后,你想想一个典型的场景,你的控制器里的某个方法里用了一个函数,函数需要一个巨大的数组参数,然后函数还需要修改这个巨大的数组参数,你们应该是函数的运行范围里面修改这个数组,所以此时会发生写时拷贝了,当函数运行完毕后,就得赶紧释放掉这块儿内存以供给其他进程使用,而不是非得等到本地fpm request彻底完成后才销毁。
(1)fpm运行完毕后,最后一定会gc的
(2)运行过程中,也会gc的,内存都是即用即释放的,而不是攒着非得到最后gc
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
我们在做开发的时候,常常会需要使用到时间函数,因此这篇文章就给大家分享php时间相关函数的内容,主要介绍了一些常用的时间相关函数的用法,感兴趣的朋友可以参考。
这篇文章主要介绍php中extract函数,对新手学习和理解extract函数的用处和用法有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章能有所收获,接下来小编带着大家一起了解看看。
thinkphp3.2中order方法用于对操作的结果进行排序,是模型连贯操作方法之一,相当于是select语句中的一个order by子句,用法为“$Model->where()->order()->limit()->select()”。
这篇文章主要介绍了PHP简单实现图片格式转换(jpg转png,gif转png等),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
本文实例讲述了PHP设计模式之迭代器模式Iterator。有不少朋友对于这个的问题比较感兴趣,下面小编给大家整理和分享了相关知识和资料,易于大家学习和理解,有需要的朋友可以借鉴参考,下面我们一起来了解一下吧。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008