PHP的垃圾回收机制-PHP⾼级⾯试题+详解
ps:本篇内容包括精选⾯试题与知识篇。
PHP⾯试题关于PHP的垃圾回收机制,PHP的垃圾回收机制引⽤计数 (reference counting) GC 机制,PHP可以⾃动进⾏内存管理,清除不需要的对象,PHP⾯试题分享PHP关于垃圾回收机制的⾯试题:
⾯试题篇
介绍⼀下PHP的垃圾回收机制
PHP使⽤了引⽤计数(reference counting)GC机制,同时使⽤根缓冲区机制,当php发现有存在循环引⽤的zval时,就会把其投⼊到根缓冲区,当根缓冲区达到配置⽂件中的指定数量后,就会进⾏垃圾回收,以此解决循环引⽤导致的内存泄漏问题。
1. 如果引⽤计数减少到零,所在变量容器将被清除(free),不属于垃圾;
2. 如果⼀个zval的引⽤计数减少后还⼤于0,那么它会进⼊垃圾周期。其次,在⼀个垃圾周期中,通过检查引⽤计数是否减1,并且检
查哪些变量容器的引⽤次数是零,来发现哪部分是垃圾。
每个对象都内含⼀个引⽤计数器refcount,每个reference连接到对象,计数器加1。当reference离开⽣存空间或被设为 NULL,计数器减1。当某个对象的引⽤计数器为零时,PHP知道你将不再需要使⽤这个对象,释放其所占的内存空间。
下列关于PHP垃圾回收的说法,错误的是?
A、开启/关闭垃圾回收机制可以通过修改php配置实现
B、可以在程序中使⽤gc_enable() 和 gc_disable()开启和关闭。
C、PHP中的垃圾回收机制,会⼤幅度提升系统性能。
D、开启垃圾回收机制后,针对内存泄露的情况,可以节省⼤量的内存空间,但是由于垃圾回收算法运⾏耗费时间,开启垃圾回收算法会增加脚本的执⾏时间。
参考答案:C
autumn翻译答案解析:PHP中的垃圾回收机制,仅仅在循环回收算法确实运⾏时会有时间消耗上的增加。但是在平常的(更⼩的)脚本中应根本就没有性能影响。
php垃圾回收机制的说法错误的是?
A、在⼀个垃圾周期中,通过检查引⽤计数是否减1,并且检查哪些变量容器的引⽤次数是零,来发现哪部分是垃圾
B、可以通过调⽤gc_enable() 和 gc_disable()函数来打开和关闭垃圾回收机制
C、通过清理未被使⽤的变量来节省内存的占⽤
D、php代码执⾏完毕后会⾃动执⾏垃圾回收,所以不需要⼿动执⾏垃圾回收
参考答案:D
答案解析:php⼀段代码有可能要长时间执⾏,但若此期间有未引⽤的变量的话,就会占⽤内存的空间,导致运⾏缓慢等问题
知识篇
⼀、概念
垃圾回收是⼀个多数编程语⾔中都带有的内存管理机制。与⾮托管性语⾔相反:C, C++ 和 Objective C,⽤户需要⼿动收集内
存,带有 GC 机制的语⾔:Java, javaScript 和 PHP 可以⾃动管理内存。
垃圾回收机制(gc)顾名思义,就是废物重利⽤的意思,是⼀种动态存储分配的⽅案。它会⾃动释放程序不再需要的已分配的内存块。垃圾回收机制可以让程序员不必过分关⼼程序内存分配,从⽽将更多的精⼒投⼊到业务逻辑。
在现在的流⾏各种语⾔当中,垃圾回收机制是新⼀代语⾔所共有的特征,如Python、PHP、C#、Ruby等都使⽤了垃圾回收机制。
⼆、PHP垃圾回收机制
1、在PHP5.3版本之前,使⽤的垃圾回收机制是单纯的“引⽤计数”。
什么叫做引⽤计数?
由于PHP是⽤C来写的,C⾥⾯有⼀种东西叫做结构体,我们PHP的变量在C中就是⽤这种⽅式存储的。
每个PHP的变量都存在于⼀个叫做zval的容器中,⼀个zval容器,除了包含变量名和值,还包括两个字节的额外信息:
● ⼀个叫做'is_ref',是个布尔值,⽤来表⽰这个变量是否属于引⽤集合,通过这个字节,我们php才能把普通变量和引⽤变量区
分开来。
● 第⼆个额外字节就是'refcount',⽤来表⽰指向这个容器的变量的个数。
即:
①每个内存对象都分配⼀个计数器,当内存对象被变量引⽤时,计数器+1;
②当变量引⽤撤掉后(执⾏unset()后),计数器-1;
③当计数器=0时,表明内存对象没有被使⽤,该内存对象则进⾏销毁,垃圾回收完成。
并且PHP在⼀个⽣命周期结束后就会释放此进程/线程所占的内容,这种⽅式决定了PHP在前期不需要过多考虑内存的泄露问题。
但是当两个或多个对象互相引⽤形成环状后,内存对象的计数器则不会消减为0;这时候,这⼀组内存对象已经没⽤了,但是不能回收,从⽽导致内存泄露的现象。
php5.3开始,使⽤了新的垃圾回收机制,在引⽤计数基础上,实现了⼀种复杂的算法,来检测内存对象中引⽤环的存在,以避免内存泄露。
2、随着PHP的发展,PHP开发者的增加以及其所承载的业务范围的扩⼤,在PHP5.3中引⼊了更加完善的垃圾回收机制,新的垃圾回
web编程语言有哪些收机制解决了⽆法处理循环的引⽤内存泄漏问题。
如官⽅⽂档所说:每个php变量存在⼀个叫"zval"的变量容器中。⼀个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息。第⼀个是"is_ref",是个bool值,⽤来标识这个变量是否是属于引⽤集合(reference set)。通过这个字节,php引擎才能把普通变量和引⽤变量区分开来,由于php允许⽤户通过使⽤&来使⽤⾃定义引⽤,zval变量容器中还有⼀个内部引⽤计数机制,来优化内存使⽤。
第⼆个额外字节是"refcount",⽤以表⽰指向这个zval变量容器的变量(也称符号即symbol)个数。所有的符号存在⼀个符号表中,其中每个符号都有作⽤域(scope)。
官⽅⽂档所说,可以使⽤Xdebug来检查引⽤计数情况:
<?php
mysql面试题及讲解
$a = "new string";
$c = $b = $a;
xdebug_debug_zval( 'a' );
unset( $b, $c );
字符串常量是用一对单引号括起来的字符序列选择对与错xdebug_debug_zval( 'a' );
?>
以上例程会输出:
a: (refcount=3, is_ref=0)='new string'
a: (refcount=1, is_ref=0)='new string'
注意:从PHP7的NTS版本开始,以上例程的引⽤将不再被计数,即$c=$b=$a之后a的引⽤计数也是1.具体分类如下:
在PHP 7中,zval可以被引⽤计数或不被引⽤。在zval结构中有⼀个标志确定了这⼀点。
①对于null,bool,int和double的类型变量,refcount永远不会计数;
②对于对象、资源类型,refcount计数和php5的⼀致;
③对于字符串,未被引⽤的变量被称为“实际字符串”。⽽那些被引⽤的字符串被重复删除(即只有⼀个带有特定内容的被插⼊的字符串)并保证在请求的整个持续时间内存在,所以不需要为它们使⽤引⽤计数;如果使⽤了opcache,这些字符串将存在于共享内存中,在这种情况下,您不能使⽤引⽤计数(因为我们的引⽤计数机制是⾮原⼦的);
④对于数组,未引⽤的变量被称为“不可变数组”。其数组本⾝计数与php5⼀致,但是数组⾥⾯的每个键值对的计数,则按前⾯三条的规则(即如果是字符串也不在计数);如果使⽤opcache,则代码中的常量数组⽂字将被转换为不可变数组。ddctf2020
再次,这些⽣活在共享内存,因此不能使⽤refcounting。
我们的demo例⼦如下:
<?php
echo '测试字符串引⽤计数';
$a = "new string";
$b = $a;
xdebug_debug_zval( 'a' );
unset( $b);
xdebug_debug_zval( 'a' );
$b = &$a;
xdebug_debug_zval( 'a' );
echo '测试数组引⽤计数';
$c = array('a','b');
xdebug_debug_zval( 'c' );
$d = $c;
xdebug_debug_zval( 'c' );
$c[2]='c';
xdebug_debug_zval( 'c' );
echo '测试int型计数';
$e = 1;
xdebug_debug_zval( 'e' );
看到的输出如下:
三、回收周期
默认的,PHP的垃圾回收机制是打开的,然后有个php.ini设置允许你修改它:able_gc 。
当垃圾回收机制打开时,算法会判断每当根缓存区存满时,就会执⾏循环查。根缓存区有固定的⼤⼩,默认10,000,可以通过修改PHP源码⽂件Zend/zend_gc.c中的常量GC_ROOT_BUFFER_MAX_ENTRIES,然后重新编译PHP,来修改这个值。当垃圾回收机制关闭时,循环查算法永不执⾏,然⽽,根将⼀直存在根缓冲区中,不管在配置中垃圾回收机制是否激活。
除了修改配置able_gc ,也能通过分别调⽤gc_enable() 和 gc_disable()函数在运⾏php时来打开和关闭垃圾回收机制。调⽤这些函数,与修改配置项来打开或关闭垃圾回收机制的效果是⼀样的。即使在可能根缓冲区还没满时,也能强制执⾏周期回收。你能调⽤
gc_collect_cycles()函数达到这个⽬的。这个函数将返回使⽤这个算法回收的周期数。
允许打开和关闭垃圾回收机制并且允许⾃主的初始化的原因,是由于你的应⽤程序的某部分可能是⾼时效性的。在这种情况下,你可能不想使⽤垃圾回收机制。当然,对你的应⽤程序的某部分关闭垃圾回收机制,是在冒着可能内存泄漏的风险,因为⼀些可能根也许存不进有限的根缓冲区。
因此,就在你调⽤gc_disable()函数释放内存之前,先调⽤gc_collect_cycles()函数可能⽐较明智。因
为这将清除已存放在根缓冲区中的所有可能根,然后在垃圾回收机制被关闭时,可留下空缓冲区以有更多空间存储可能根。
四、性能影响
1、内存占⽤空间的节省
⾸先,实现垃圾回收机制的整个原因是为了⼀旦先决条件满⾜,通过清理循环引⽤的变量来节省内存占⽤。在PHP执⾏中,⼀旦根缓冲区满了或者调⽤gc_collect_cycles() 函数时,就会执⾏垃圾回收。
2、执⾏时间增加
垃圾回收影响性能的第⼆个领域是它释放已泄漏的内存耗费的时间。
通常,PHP中的垃圾回收机制,仅仅在循环回收算法确实运⾏时会有时间消耗上的增加。但是在平常的(更⼩的)脚本中应根本就没有性能影响。
3、在平常脚本中有循环回收机制运⾏的情况下,内存的节省将允许更多这种脚本同时运⾏在你的服务器上。因为总共使⽤的内存没达到上限。
这种好处在长时间运⾏脚本中尤其明显,诸如长时间的测试套件或者daemon脚本此类。同时,对通常⽐Web脚本运⾏时间长的脚本应⽤程序,新的垃圾回收机制,应该会⼤⼤改变⼀直以来认为内存泄漏问题难以解决的看法。
最后,祝所有⼤家在⾯试中过关斩将,拿到⼼仪offer。
对此我整理了⼀些资料,包括但不限于:分布式架构、⾼可扩展、⾼性能、⾼并发、服务器性能调优、
TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点⾼级进阶⼲货需要的可以免费分享给⼤家
如果想与⼀3-8年资深开发者⼀起交流学习的话,需要,我的官⽅-。
本⽂由博客发⼀⽂多发等运营⼯具平台发布
synchronized面试题

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。