首页 » Web前端 » php916技巧_PHP 垃圾收受接收机制

php916技巧_PHP 垃圾收受接收机制

访客 2024-12-14 0

扫一扫用手机浏览

文章目录 [+]

PHP进行内存管理的核心算法一共两项:一是引用计数,二是写时拷贝。
当你声明一个PHP变量的时候,C措辞就在底层给你搞了一个叫做zval的struct(构造体);如果你还给这个变量赋值了,比如“hello world”,那么C措辞就在底层再给你搞一个叫做zend_value的union(联合体)

PHP垃圾回收机制是 php5 之后才有的这个东西,php5.3 之前利用的垃圾回收机制是纯挚的“引用计数”,便是每个内存工具都分配一个计数器,当内存工具被变量引用时,计数器+ 1;当变量引用撇掉后,计数器 -1 ;当计数器 =0 时,表名内存中工具没有被利用,该内存工具进行销毁,垃圾回收完成;

php916技巧_PHP 垃圾收受接收机制

php5.3开始,利用了新的垃圾回收机制,在引用计数根本上,实现了一种繁芜的算法,来检测内存工具中 引用环 的存在,以避免内存透露;

php916技巧_PHP 垃圾收受接收机制
(图片来自网络侵删)
引用计数基本知识

每个php变量存在一个叫"zval"的变量容器中。
一个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息。
第一个是"is_ref",是个bool值,用来标识这个变量是否是属于引用凑集(reference set)。
通过这个字节,php引擎才能把普通变量和引用变量区分开来,由于php许可用户通过利用&来利用自定义引用,zval变量容器中还有一个内部引用计数机制,来优化内存利用。
第二个额外字节是"refcount",用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。
所有的符号存在一个符号表中,个中每个符号都有浸染域(scope),那些主脚本(比如:通过浏览器要求的的脚本)和每个函数或者方法也都有浸染域。

zval { string "a" //变量的名字是a value zend_value //变量的值 type string //变量是字符串类型}zend_value { string "hello916" //值的内容 refcount 1 //引用计数}

<?php $a = 'hello'. mt_rand( 1, 1000 );xdebug_debug_zval( 'a');$b = $a;xdebug_debug_zval('a');$c = $a;xdebug_debug_zval('a');unset( $c );xdebug_debug_zval( 'a');// 输出结果a: (refcount=1, is_ref=0)='hello517'a: (refcount=2, is_ref=0)='hello517'a: (refcount=3, is_ref=0)='hello517'a: (refcount=2, is_ref=0)='hello517'

个中,zval struct构造体用于保存$a,zend_value union联合体用于保存数据内容也便是'hello517'。
由于后面又声明了b和c,以是C不得不又在底层给你搞出两个zval struct构造体来。

那么写时拷贝是什么意思呢?看下面代码:

<?php $a = 'hello'. mt_rand( 1, 1000 );$b = $a;xdebug_debug_zval( 'a');$a = 'world'. mt_rand( 2, 2000 );xdebug_debug_zval( 'a');// 输出结果a: (refcount=2, is_ref=0)='hello834'a: (refcount=1, is_ref=0)='world1198'

引用计数和写时拷贝,那么垃圾回收也该来了。
当一个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种两种情形:

数组:a数组的某个成员利用&引用a自己 工具:工具的某个成员引用工具自己

<?php$arr = [ 1 ];$arr[] = &$arr;unset( $arr );

这种情形下,zend_value不会能开释,但也不能放过它,不然一定会产生内存泄露,以是这会儿zend_value会被扔到一个叫做垃圾回收堆中,然后zend引擎会依次对垃圾回收堆中的这些zend_value进行二次检测,检测是不是由于上述两种情形造成的refcount为1但是自身却确实没有人再用了,如果一旦确定是上述两种情形造成的,那么就会将zend_value彻底抹掉开释内存。

那么垃圾回收发生在什么时候?有些同学可能有疑问,便是php不是运行一次就销毁了吗,我要着gc有何用?并不是啦,首先当一次fpm运行完毕后,末了一定还有gc的,这个销毁便是gc;其次是,内存都是即用即开释的,而不是攒着非得到末了,你想想一个范例的场景,你的掌握器里的某个方法里用了一个函数,函数须要一个巨大的数组参数,然后函数还须要修正这个巨大的数组参数,你们该当是函数的运行范围里面修正这个数组,以是此时会发生写时拷贝了,当函数运行完毕后,就得赶紧开释掉这块儿内存以供给其他进程利用,而不是非得等到本地fpm request彻底完成后才销毁。

PHP5 和 PHP7的来及回收机制有什么不同

PHP5 和 PHP7 的垃圾回收机制都属于引用计数,但是繁芜数据类型的算法处理上:在PHP7中zval有了新的实现办法。

最根本的变革是zval须要的内存不再是单独从堆上分配,不再自己存储引用计数繁芜数据类型(比如字符串、数组和工具)的引用计数由其自身来存储

这种实现办法有以下好处:

大略数据类型不须要单独分配内存,也不须要计数;不会再有两次计数的情形。
在工具中,只有工具自身存储的计数是有效的;由于现在计数由数值自身存储,以是也就可以和非 zval 构造的数据共享,比如 zval 和 hashtable key 之间;
标签:

相关文章

大数据时代下的澳洲,机遇与挑战并存

随着互联网技术的飞速发展,大数据已经成为当今世界的重要战略资源。作为全球科技创新的领跑者,澳洲在大数据领域也展现出独特的魅力。本文...

Web前端 2024-12-16 阅读0 评论0