当前位置: 首页 > 后端技术 > PHP

PHP垃圾回收机制

时间:2023-03-29 15:20:41 PHP

PHP是一种弱类型的脚本语言。弱类型并不意味着PHP变量没有类型差异。PHP变量有8种基本类型:四种标量类型:布尔(Boolean)整型(integer))浮点型(floatingpointtype)两种复合类型:数组(array)对象(object)两种特殊类型:资源(resource)NULL引擎内部,变量由结构表示。这个结构可以在{PHPSRC}/Zend/zend.h中找到:struct_zval_struct{/*变量信息*/zvalue_valuevalue;/*值*/zend_uintrefcount__gc;//代表一个计数器,表示有多少个变量名指向这个zval容器zend_uchar类型;/*活动类型*/zend_ucharis_ref__gc;//该字段为布尔值,用于标识变量是否为引用,PHP引擎通过该字段可以区分普通变量和引用变量};写时复制(copy-on-writetechnology)父进程fork子进程后,子进程的地址空间仍然简单地指向父进程的地址空间。只有当子进程需要写入地址空间中的内容时,才会单独单独复制一份用于这样子进程即使立即调用exec函数也没有关系,因为不需要复制内容完全来自父进程的地址空间,这样可以节省内存,同时提高速度。这个逻辑可以描述为:对一个通用变量a(isref=0)进行通用赋值操作,如果a指向的zval的countrefcount大于1,则需要重新给a赋值一个新的zval,而之前的zvalrefcount的计数减1。PHP5.3中新的GC算法(ConcurrentCycleCollectioninReferenceCountedSystems)的几个基本准则:如果一个zval的refcount增加了,那么这个zval还在使用中,不是垃圾。如果一个zval的refcount减少到0,那么这个zval就可以被释放,它不是垃圾。如果一个zval被reduce后refcount大于0,那么这个zval就不能被释放,zval就可能变成垃圾。新的GC算法的目的是防止循环引用的变量造成内存泄漏。在PHP中的GC算法中,当节点缓冲区满时,就会启动垃圾分析算法,将发现的垃圾释放,从而回收内存。现在,如果我们尝试将数组引用分配给数组中的元素,会发生一些有趣的事情:$a数组有两个元素,一个索引为0,值为字符一,另一个索引为1,是$a本身的引用,内部存储如下:a:(refcount=2,is_ref=1)=array(0=>(refcount=1,is_ref=0)='one',1=>(refcount=2,is_ref=1)=...)"..."表示1指向a本身,这是一个循环引用(Circularreference):这时候我们unset$a,那么$a就会从符号表中删除,$a指向的zval的refcount就会减1。那么问题来了,$a已经不在符号表中了,用户不能再访问这个变量,但是$a指向的zval的refcount变成了1而不是0,所以不能回收,从而造成内存泄漏:这样zval就变成了垃圾,newGC的工作就是清理这个垃圾。在PHP编程中,程序员不需要手动处理内存资源的分配和释放,也就是说PHP本身实现了垃圾回收机制。PHP5.2中的垃圾回收算法---ReferenceCounting,简称“引用计数”。总是有一个引用这个对象的变量),每有一个新的变量引用这个内存对象,计数器就加1,每当有一个引用这个内存对象的变量减少,计数器就为减1。垃圾回收机制运行时,销毁所有计数器为0的内存对象,回收它们占用的内存。php中的内存对象是zval,计数器是refcount__gc。