数码资讯
的PHP5.3的垃圾回收机制的深刻理解(动态存储分配方案)
垃圾回收机制是一个动态存储分配方案。它会自动释放分配的内存块,程序不再需要的内存自动回收的过程被称为垃圾收集,垃圾收集机制允许程序员更关注业务逻辑,而不必关心程序的内存分配太多。在目前的流行的语言,语言的垃圾回收机制是新一代的一个共同的特点,如Python,PHP,Eiffel,C #、露比等,其中
选购提示
关注价格、性能、续航、售后和真实使用场景,理性比较后再下单。
垃圾回收机制是一个动态存储分配方案。它会自动释放分配的内存块,程序不再需要的内存自动回收的过程被称为垃圾收集,垃圾收集机制允许程序员更关注业务逻辑,而不必关心程序的内存分配太多。在目前的流行的语言,语言的垃圾回收机制是新一代的一个共同的特点,如Python,PHP,Eiffel,C #、露比等,其中使用垃圾收集机制。虽然垃圾收集是现在流行的,不是太年轻,由麻省理工学院在上世纪60年代开发的LISP系统早已经在它的存在,但因为SE技术条件的成熟,使垃圾收集机制已成为一个不错的技术,直到上个世纪90年代,java,垃圾收集机制被广泛应用。
PHP还实现了语言层中内存的动态管理,在前面的章节中已经详细地解释过了。内存的动态管理有助于开发人员摆脱繁琐的内存管理,PHP还提供了语言层中的垃圾收集机制,让程序员不必太在意程序内存分配。
在PHP5.3版,php有简单的垃圾收集基于引用计数。当一个变量的引用计数变为0时,PHP将在内存中销毁这个变量,但是这里的垃圾不能称为垃圾,PHP将在生命周期结束后释放进程线程的内容。这种方式决定了PHP不需要想太多关于内存泄漏的早期阶段。但是随着PHP开发,PHP开发人员,其业务范围的扩大增加了一个更完美php5.3.the新垃圾收集机制的垃圾收集机制解决了不能处理循环引用的内存泄漏的问题。在PHP5.3的垃圾回收机制采用同步算法在并行循环采集在引用计数系统。作为该算法的介绍,我们将不再描述它。在PHP的官方文档中,有一个关于恢复周期的介绍(收集周期)。
如前所述,在PHP中,主存管理方法是按引用计数的。介绍垃圾收集机制的目的是要打破引用计数的循环引用,从而防止由于内存泄漏,垃圾收集机制是基于PHP的动态内存管理。为了引进的垃圾收集机制,PHP5.3在变量存储的基本结构有一些变化,如下面所示:
复制代码代码如下所示:
结构_zval_struct {
变量信息
zvalue_value值; / * * /
zend_uint refcount__gc;
zend_uchar型活跃型; / * * /
zend_uchar is_ref__gc;
};
与以前的版本相比,PHP5.3,参考计数字段引用计数和字段是否is_ref参考已添加__gc背后的新的垃圾收集机制,PHP源码的风格,大量的宏是一个非常明显的特征。这些宏是相当于一个接口层,其中下面的底层接口层,如alloc_zval,宏碁,宏碁是内存管理的内存分配函数直接调用PHP emalloc分配的内存大小在PHP5.3,通过变量如大小决定的类型。在垃圾收集的介绍,直接使用alloc_zval宏观结构新的垃圾收集装置的尺寸分布同样的,都是ZVal_gc_info结构的内存大小和内存分配和垃圾收集机制初始化结构。下面的代码:
复制代码代码如下所示:
以下宏覆盖宏从 / * * / zend_alloc。H
# undef alloc_zval
#定义alloc_zval(Z)
做{
(Z)=(zval *)emalloc(sizeof(zval_gc_info));
gc_zval_init(Z);
而(0)}
的zend_gc .h文件是在749线参考:Zend。H #包括zend_gc。H在237行中引用的zend_alloc更换盖。h文件alloc_zval宏在宏的新变化,关键是分配的内存的大小和分布在以前的纯粹的垃圾收集机制的内容增加了内存分配的内容的变化,包括在zval_gc_info结构的所有内容:
复制代码代码如下所示:
_zval_gc_info { typedef struct
变量z;
联盟{
gc_root_buffer *缓冲;
结构_zval_gc_info *下;
u };
zval_gc_info };
任何变量存储在一个变量的容器,一个zval结构分配,以确保它是由变量变量分配的内存对齐,以便它可以被用来作为变量时zval_gc_info型指针是被迫的。变量场后,有一个联盟:美国U包括缓冲领域的gc_root_buffer结构和下一场的zval_gc_info结构。这两个领域代表的垃圾回收机制的缓存的根节点,一个是对zval_gc_info列表中的下一个节点,和垃圾收集机制的节点可以反映在根节点和列表node.alloc_zval电话gc_zval_init初始化已分配的内存替换变量zval_gc_info,它将把缓冲在美国的zval_gc_info成员字段设置为空,只有在这一领域进入垃圾收集缓冲区也有一定的价值,否则将是无效的。因为在zval变量的形式存在,PHP中的所有变量,而变量,zval_gc_info实现原系统中的垃圾回收机制整合。
PHP的垃圾回收机制是默认的PHP5.3打开,但我们可以把它直接通过配置文件和相应的配置领域zend.enable_gc.in php.ini文件,没有字段的默认。如果我们需要禁用该功能,添加Zend。enable_gc = 0或Zend。enable_gc =在php.ini.in除了修改php.ini配置zend.enable_gc,您也可以打开或关闭通过调用gc_enable垃圾收集机制()/ gc_disable()函数,这些函数的作用就是修饰配置项来打开或关闭的垃圾收集机制相同。除了这两个函数,PHP提供了gc_collect_cycles()函数,可以强制执行周期恢复时,根缓冲区是不完整的。是否垃圾收集机制开辟了一些相关业务领域的PHP源代码中。Zend。C文件,有下面的代码:
复制代码代码如下所示:
静态zend_ini_mh(onupdategcenabled) / / *
{
onupdatebool(入境,new_value,new_value_length,mh_arg1,mh_arg2,mh_arg3,阶段tsrmls_cc);
如果(gc_g(gc_enabled)){
gc_init(tsrmls_c);
}
返回成功;
}
zend_ini_begin()
zend_ini_entry(error_reporting
STD_ZEND_INI_BOOLEAN (zend.enable_gc
# ifdef zend_multibyte
std_zend_ini_boolean(detect_unicode
# endif
zend_ini_end()
相应的操作功能,zend.enable_gc zend_ini_mh(onupdategcenabled)。如果一开始我们的垃圾收集机制,这是gc_g(gc_enabled)是真的,那么我们称gc_init函数执行垃圾收集机制的初始化操作,gc_init功能是Zend / zend_gc C 121线。这个函数将决定是否打开垃圾收集机制。如果它被打开,它将是整个机制,直接调用malloc分配内存空间10000 gc_root_buffer整个缓存列表。10000这是在代码中硬编码,这是基于宏观gc_root_buffer_max_entries。如果我们需要修改这个值,我们需要修改源代码并重新编译PHP,gc_init函数的全局变量在预分配的内存调用gc_reset功能后重置整个机制的使用,如设置一些统计GC操作(gc_runs)和GC垃圾数量(收集)是0、一个节点集的双向链路头节点和节点的自己。除了一些用于垃圾收集机制的全局变量,还有一些其他的变量,用的比较多,这说明如下:
复制代码代码如下所示:
_zend_gc_globals { typedef struct
zend_bool gc_enabled; / * * /是否打开垃圾收集机制
zend_bool gc_active; / * * /正在进行
gc_root_buffer * buf; / *预分配的缓冲区数组,默认值是10000(预分配数组的缓冲区)。
gc_root_buffer根; / *根节点列表(周期的可能的根目录)。
gc_root_buffer *闲置; / *缓冲区列表中未使用的(未使用的缓冲区列表)。
gc_root_buffer * first_unused; / *是指第一个未使用的缓存节点(先不用的缓冲区指针)。
gc_root_buffer * last_unused; / *点到最后一个在这里没有使用缓冲节点,标记使用结束(指针上未使用的缓冲区)。
zval_gc_info * zval_to_free; / *在zval释放变量的临时表(temporaryt自由zvals列表)。
zval_gc_info * free_list; / *临时变量,需要在开始发布名单。
zval_gc_info * next_to_free; / *临时变量,一个变量的位置将被释放。
zend_uint gc_runs;统计* / / * GC操作
zend_uint收集垃圾;数GC / * * /
省略…
}
当我们使用撤消操作此变量删除记忆(这可能是一个引用计数减一),将在当前符号的变量名对应的哈希表中删除,所有的运作实施后,调用删除项目符号表中的功能分析。临时变量会叫zval_dtor,一般变会叫zval_ptr_dtor。
当然,我们不能在PHP的函数集找到设置功能,因为它是一种语言结构,相应的中间代码是zend_unset,在Zend / zend_vm_execute。h文件中你可以找到有关它的实施。
zval_ptr_dtor不是功能,而是一个宏是一个有点像一个函数,在Zend / zend_variables。h文件,这个宏点的功能_zval_ptr_dtor.in Zend / zend_execute_api。C 424线、功能相关的代码如下:
复制代码代码如下所示:
zend_api无效_zval_ptr_dtor(zval ** zval_ptr zend_file_line_dc) / / *
{
#如果debug_zend > = 2
printf(减少引用计数(% % X X):%d - %d
# endif
z_delref_pp(zval_ptr);
如果(z_refcount_pp(zval_ptr)= = 0){
tsrmls_fetch();
如果zval_ptr(*!=如(uninitialized_zval)){
gc_remove_zval_from_buffer(* zval_ptr);
zval_dtor(* zval_ptr);
efree_rel(* zval_ptr);
}
{人}
tsrmls_fetch();
如果(z_refcount_pp(zval_ptr)= = 1){
z_unset_isref_pp(zval_ptr);
}
gc_zval_check_possible_root(* zval_ptr);
}
}
从代码中我们可以清楚地看到在zval解构的过程,并在之后的两个操作都在引用计数方面做的:
如果变量的引用计数是1,也就是说,在引用计数为0之后,一个负号被直接清除,如果当前变量被缓存,那么我们需要清除缓存。如果变量的引用计数大于1,也就是说,当引用计数减少到0以上时,变量将被放置在垃圾列表中。如果引用存在,则删除其引用。
把变量列表操作gc_zval_check_possible_root垃圾。这也是一个宏,gc_zval_check_possible_root对应函数,但这个函数只执行垃圾收集操作数组和对象,数组和对象变量,调用gc_zval_possible_root功能。
复制代码代码如下所示:
zend_api无效gc_zval_possible_root(zval * ZV tsrmls_dc)
{
如果(意外(gc_g(free_list)!= null
gc_zval_address(ZV)!= null
gc_zval_get_color(ZV)= gc_black)
(gc_zval_address(ZV)< gc_g(BUF)| |
gc_zval_address(ZV)= gc_g(last_unused))){
给定的变量是一个垃圾,将被删除
*当前正在运行GC * /
返回;
}
如果(ZV ->型= = is_object){
gc_zobj_check_possible_root(ZV);
返回;
}
gc_bench_inc(zval_possible_root);
如果(gc_zval_get_color(ZV)!= gc_purple){
gc_zval_set_purple(ZV);
如果(!gc_zval_address(ZV)){
gc_root_buffer * newroot = gc_g(未使用);
如果(newroot){
gc_g(未使用)= newroot ->沪指;
} else if(gc_g(first_unused)!= gc_g(last_unused)){
newroot = gc_g(first_unused);
gc_g(first_unused)+ +;
{人}
如果(!gc_g(gc_enabled)){
gc_zval_set_black(ZV);
返回;
}
ZV -> refcount__gc + +;
gc_collect_cycles(tsrmls_c);
ZV -> refcount__gc --;
newroot = gc_g(未使用);
如果(!NewRoot){
返回;
}
gc_zval_set_purple(ZV);
gc_g(未使用)= newroot ->沪指;
}
newroot ->下= gc_g(根),下;
newroot -> prev = gc_g(根);
gc_g(根)下-> newroot进程;
gc_g(根)newroot下=;
gc_zval_set_address(ZV,newroot);
newroot ->处理= 0;
newroot -> u.pz =∑;
gc_bench_inc(zval_buffered);
gc_bench_inc(root_buf_length);
gc_bench_peak(root_buf_peak,root_buf_length);
}
}
}
如前所述,gc_zval_check_possible_root函数只执行垃圾收集操作数组和对象。然而,在gc_zval_possible_root功能,gc_zobj_check_possible_root宏称为对象类型的变量,其他变量类型,可用于垃圾收集,调用过程如下:
检查是否已投入变量节点信息节点的缓冲区,如果它已在节点的缓冲区,它直接返回,并优化其性能。然后处理对象的节点直接,不执行以下操作来决定节点是否已标记为紫色。如果它是紫色的,它将不再被添加到节点缓冲区。这是为了确保一个节点只执行一个添加到缓冲区的操作。
将节点的颜色标记为紫色,表示此节点已添加到缓冲区,下一次将不被添加。
找出新节点的位置,如果缓冲区已满,则执行垃圾回收操作。
在缓冲区所在的双向链表中添加一个新节点。
在gc_zval_possible_root功能,当缓冲区满,程序调用gc_collect_cycles函数来执行垃圾回收操作中最关键的步骤:
这里的第六百二十八行作为它的官方文档算法B步算法,利用深度优先搜索查找所有可能的根,将每个容器中的变量引用计数为1,以确保没有相同变量的容器减去两次1,使用灰色标记已经减少了1以上。
第六百二十九行是该算法的步骤C,再次使用每个根节点检查每个变量的容器的引用计数的深度优先搜索。如果引用计数为0,可变容器是白色标记。如果引用的数量大于0,那么我们恢复使用深度首先搜索到1,这是减少引用计数操作,引用计数加1,然后再把它标记为黑色。
第六百三十行的算法的最后一步是D算法遍历删除变量容器根缓冲(zval根),并检查是否有白色标记在前一步变容器,每个容器标有白色的变量被清除。在{ gc_collect_cycles(gc_collect_roots)->()(zval_collect_white)},我们可以看到,白色标记的节点将被添加到全局变量zval_to_free.this列表的列表是有用的后续操作。
PHP的垃圾收集机制在执行过程中被标记为四种颜色。
gc_white白色意味着垃圾
gc_purple紫色表明它已被放置在一个缓冲区
灰色gc_grey表明一个引用计数减操作了
gc_black黑色是默认的颜色,正常
相关的标记和操作代码如下所示:
复制代码代码如下所示:
#定义gc_color 0x03
#定义gc_black 0x00
#定义gc_white 0x01
#定义gc_grey 0x02
#定义gc_purple 0x03
#定义gc_address(V)
((gc_root_buffer *)(((zend_uintptr_t)(v))~ gc_color)))
#定义gc_set_address(V,A)
((V)=(gc_root_buffer *)((((zend_uintptr_t)(v))|(gc_color)(zend_uintptr_t)(一))))
#定义gc_get_color(V)
(((zend_uintptr_t)(v))gc_color)
#定义gc_set_color(V,C)
((V)=(gc_root_buffer *)((((zend_uintptr_t)~ gc_color(V)))|(C)))
#定义gc_set_black(V)
(v)=((gc_root_buffer *)(((zend_uintptr_t)(v))~ gc_color)))
#定义gc_set_purple(V)
((V)=(gc_root_buffer *)(((zend_uintptr_t)gc_purple(V))|))
上面的逐位标记方式在PHP的源代码中很有用,如内存管理等,这是一种高效和经济的解决方案,但是当我们进行数据库设计时,我们可能无法使用这种方法来实现字段。应该以更直观、更易读的方式实现它。
PHP还实现了语言层中内存的动态管理,在前面的章节中已经详细地解释过了。内存的动态管理有助于开发人员摆脱繁琐的内存管理,PHP还提供了语言层中的垃圾收集机制,让程序员不必太在意程序内存分配。
在PHP5.3版,php有简单的垃圾收集基于引用计数。当一个变量的引用计数变为0时,PHP将在内存中销毁这个变量,但是这里的垃圾不能称为垃圾,PHP将在生命周期结束后释放进程线程的内容。这种方式决定了PHP不需要想太多关于内存泄漏的早期阶段。但是随着PHP开发,PHP开发人员,其业务范围的扩大增加了一个更完美php5.3.the新垃圾收集机制的垃圾收集机制解决了不能处理循环引用的内存泄漏的问题。在PHP5.3的垃圾回收机制采用同步算法在并行循环采集在引用计数系统。作为该算法的介绍,我们将不再描述它。在PHP的官方文档中,有一个关于恢复周期的介绍(收集周期)。
如前所述,在PHP中,主存管理方法是按引用计数的。介绍垃圾收集机制的目的是要打破引用计数的循环引用,从而防止由于内存泄漏,垃圾收集机制是基于PHP的动态内存管理。为了引进的垃圾收集机制,PHP5.3在变量存储的基本结构有一些变化,如下面所示:
复制代码代码如下所示:
结构_zval_struct {
变量信息
zvalue_value值; / * * /
zend_uint refcount__gc;
zend_uchar型活跃型; / * * /
zend_uchar is_ref__gc;
};
与以前的版本相比,PHP5.3,参考计数字段引用计数和字段是否is_ref参考已添加__gc背后的新的垃圾收集机制,PHP源码的风格,大量的宏是一个非常明显的特征。这些宏是相当于一个接口层,其中下面的底层接口层,如alloc_zval,宏碁,宏碁是内存管理的内存分配函数直接调用PHP emalloc分配的内存大小在PHP5.3,通过变量如大小决定的类型。在垃圾收集的介绍,直接使用alloc_zval宏观结构新的垃圾收集装置的尺寸分布同样的,都是ZVal_gc_info结构的内存大小和内存分配和垃圾收集机制初始化结构。下面的代码:
复制代码代码如下所示:
以下宏覆盖宏从 / * * / zend_alloc。H
# undef alloc_zval
#定义alloc_zval(Z)
做{
(Z)=(zval *)emalloc(sizeof(zval_gc_info));
gc_zval_init(Z);
而(0)}
的zend_gc .h文件是在749线参考:Zend。H #包括zend_gc。H在237行中引用的zend_alloc更换盖。h文件alloc_zval宏在宏的新变化,关键是分配的内存的大小和分布在以前的纯粹的垃圾收集机制的内容增加了内存分配的内容的变化,包括在zval_gc_info结构的所有内容:
复制代码代码如下所示:
_zval_gc_info { typedef struct
变量z;
联盟{
gc_root_buffer *缓冲;
结构_zval_gc_info *下;
u };
zval_gc_info };
任何变量存储在一个变量的容器,一个zval结构分配,以确保它是由变量变量分配的内存对齐,以便它可以被用来作为变量时zval_gc_info型指针是被迫的。变量场后,有一个联盟:美国U包括缓冲领域的gc_root_buffer结构和下一场的zval_gc_info结构。这两个领域代表的垃圾回收机制的缓存的根节点,一个是对zval_gc_info列表中的下一个节点,和垃圾收集机制的节点可以反映在根节点和列表node.alloc_zval电话gc_zval_init初始化已分配的内存替换变量zval_gc_info,它将把缓冲在美国的zval_gc_info成员字段设置为空,只有在这一领域进入垃圾收集缓冲区也有一定的价值,否则将是无效的。因为在zval变量的形式存在,PHP中的所有变量,而变量,zval_gc_info实现原系统中的垃圾回收机制整合。
PHP的垃圾回收机制是默认的PHP5.3打开,但我们可以把它直接通过配置文件和相应的配置领域zend.enable_gc.in php.ini文件,没有字段的默认。如果我们需要禁用该功能,添加Zend。enable_gc = 0或Zend。enable_gc =在php.ini.in除了修改php.ini配置zend.enable_gc,您也可以打开或关闭通过调用gc_enable垃圾收集机制()/ gc_disable()函数,这些函数的作用就是修饰配置项来打开或关闭的垃圾收集机制相同。除了这两个函数,PHP提供了gc_collect_cycles()函数,可以强制执行周期恢复时,根缓冲区是不完整的。是否垃圾收集机制开辟了一些相关业务领域的PHP源代码中。Zend。C文件,有下面的代码:
复制代码代码如下所示:
静态zend_ini_mh(onupdategcenabled) / / *
{
onupdatebool(入境,new_value,new_value_length,mh_arg1,mh_arg2,mh_arg3,阶段tsrmls_cc);
如果(gc_g(gc_enabled)){
gc_init(tsrmls_c);
}
返回成功;
}
zend_ini_begin()
zend_ini_entry(error_reporting
STD_ZEND_INI_BOOLEAN (zend.enable_gc
# ifdef zend_multibyte
std_zend_ini_boolean(detect_unicode
# endif
zend_ini_end()
相应的操作功能,zend.enable_gc zend_ini_mh(onupdategcenabled)。如果一开始我们的垃圾收集机制,这是gc_g(gc_enabled)是真的,那么我们称gc_init函数执行垃圾收集机制的初始化操作,gc_init功能是Zend / zend_gc C 121线。这个函数将决定是否打开垃圾收集机制。如果它被打开,它将是整个机制,直接调用malloc分配内存空间10000 gc_root_buffer整个缓存列表。10000这是在代码中硬编码,这是基于宏观gc_root_buffer_max_entries。如果我们需要修改这个值,我们需要修改源代码并重新编译PHP,gc_init函数的全局变量在预分配的内存调用gc_reset功能后重置整个机制的使用,如设置一些统计GC操作(gc_runs)和GC垃圾数量(收集)是0、一个节点集的双向链路头节点和节点的自己。除了一些用于垃圾收集机制的全局变量,还有一些其他的变量,用的比较多,这说明如下:
复制代码代码如下所示:
_zend_gc_globals { typedef struct
zend_bool gc_enabled; / * * /是否打开垃圾收集机制
zend_bool gc_active; / * * /正在进行
gc_root_buffer * buf; / *预分配的缓冲区数组,默认值是10000(预分配数组的缓冲区)。
gc_root_buffer根; / *根节点列表(周期的可能的根目录)。
gc_root_buffer *闲置; / *缓冲区列表中未使用的(未使用的缓冲区列表)。
gc_root_buffer * first_unused; / *是指第一个未使用的缓存节点(先不用的缓冲区指针)。
gc_root_buffer * last_unused; / *点到最后一个在这里没有使用缓冲节点,标记使用结束(指针上未使用的缓冲区)。
zval_gc_info * zval_to_free; / *在zval释放变量的临时表(temporaryt自由zvals列表)。
zval_gc_info * free_list; / *临时变量,需要在开始发布名单。
zval_gc_info * next_to_free; / *临时变量,一个变量的位置将被释放。
zend_uint gc_runs;统计* / / * GC操作
zend_uint收集垃圾;数GC / * * /
省略…
}
当我们使用撤消操作此变量删除记忆(这可能是一个引用计数减一),将在当前符号的变量名对应的哈希表中删除,所有的运作实施后,调用删除项目符号表中的功能分析。临时变量会叫zval_dtor,一般变会叫zval_ptr_dtor。
当然,我们不能在PHP的函数集找到设置功能,因为它是一种语言结构,相应的中间代码是zend_unset,在Zend / zend_vm_execute。h文件中你可以找到有关它的实施。
zval_ptr_dtor不是功能,而是一个宏是一个有点像一个函数,在Zend / zend_variables。h文件,这个宏点的功能_zval_ptr_dtor.in Zend / zend_execute_api。C 424线、功能相关的代码如下:
复制代码代码如下所示:
zend_api无效_zval_ptr_dtor(zval ** zval_ptr zend_file_line_dc) / / *
{
#如果debug_zend > = 2
printf(减少引用计数(% % X X):%d - %d
# endif
z_delref_pp(zval_ptr);
如果(z_refcount_pp(zval_ptr)= = 0){
tsrmls_fetch();
如果zval_ptr(*!=如(uninitialized_zval)){
gc_remove_zval_from_buffer(* zval_ptr);
zval_dtor(* zval_ptr);
efree_rel(* zval_ptr);
}
{人}
tsrmls_fetch();
如果(z_refcount_pp(zval_ptr)= = 1){
z_unset_isref_pp(zval_ptr);
}
gc_zval_check_possible_root(* zval_ptr);
}
}
从代码中我们可以清楚地看到在zval解构的过程,并在之后的两个操作都在引用计数方面做的:
如果变量的引用计数是1,也就是说,在引用计数为0之后,一个负号被直接清除,如果当前变量被缓存,那么我们需要清除缓存。如果变量的引用计数大于1,也就是说,当引用计数减少到0以上时,变量将被放置在垃圾列表中。如果引用存在,则删除其引用。
把变量列表操作gc_zval_check_possible_root垃圾。这也是一个宏,gc_zval_check_possible_root对应函数,但这个函数只执行垃圾收集操作数组和对象,数组和对象变量,调用gc_zval_possible_root功能。
复制代码代码如下所示:
zend_api无效gc_zval_possible_root(zval * ZV tsrmls_dc)
{
如果(意外(gc_g(free_list)!= null
gc_zval_address(ZV)!= null
gc_zval_get_color(ZV)= gc_black)
(gc_zval_address(ZV)< gc_g(BUF)| |
gc_zval_address(ZV)= gc_g(last_unused))){
给定的变量是一个垃圾,将被删除
*当前正在运行GC * /
返回;
}
如果(ZV ->型= = is_object){
gc_zobj_check_possible_root(ZV);
返回;
}
gc_bench_inc(zval_possible_root);
如果(gc_zval_get_color(ZV)!= gc_purple){
gc_zval_set_purple(ZV);
如果(!gc_zval_address(ZV)){
gc_root_buffer * newroot = gc_g(未使用);
如果(newroot){
gc_g(未使用)= newroot ->沪指;
} else if(gc_g(first_unused)!= gc_g(last_unused)){
newroot = gc_g(first_unused);
gc_g(first_unused)+ +;
{人}
如果(!gc_g(gc_enabled)){
gc_zval_set_black(ZV);
返回;
}
ZV -> refcount__gc + +;
gc_collect_cycles(tsrmls_c);
ZV -> refcount__gc --;
newroot = gc_g(未使用);
如果(!NewRoot){
返回;
}
gc_zval_set_purple(ZV);
gc_g(未使用)= newroot ->沪指;
}
newroot ->下= gc_g(根),下;
newroot -> prev = gc_g(根);
gc_g(根)下-> newroot进程;
gc_g(根)newroot下=;
gc_zval_set_address(ZV,newroot);
newroot ->处理= 0;
newroot -> u.pz =∑;
gc_bench_inc(zval_buffered);
gc_bench_inc(root_buf_length);
gc_bench_peak(root_buf_peak,root_buf_length);
}
}
}
如前所述,gc_zval_check_possible_root函数只执行垃圾收集操作数组和对象。然而,在gc_zval_possible_root功能,gc_zobj_check_possible_root宏称为对象类型的变量,其他变量类型,可用于垃圾收集,调用过程如下:
检查是否已投入变量节点信息节点的缓冲区,如果它已在节点的缓冲区,它直接返回,并优化其性能。然后处理对象的节点直接,不执行以下操作来决定节点是否已标记为紫色。如果它是紫色的,它将不再被添加到节点缓冲区。这是为了确保一个节点只执行一个添加到缓冲区的操作。
将节点的颜色标记为紫色,表示此节点已添加到缓冲区,下一次将不被添加。
找出新节点的位置,如果缓冲区已满,则执行垃圾回收操作。
在缓冲区所在的双向链表中添加一个新节点。
在gc_zval_possible_root功能,当缓冲区满,程序调用gc_collect_cycles函数来执行垃圾回收操作中最关键的步骤:
这里的第六百二十八行作为它的官方文档算法B步算法,利用深度优先搜索查找所有可能的根,将每个容器中的变量引用计数为1,以确保没有相同变量的容器减去两次1,使用灰色标记已经减少了1以上。
第六百二十九行是该算法的步骤C,再次使用每个根节点检查每个变量的容器的引用计数的深度优先搜索。如果引用计数为0,可变容器是白色标记。如果引用的数量大于0,那么我们恢复使用深度首先搜索到1,这是减少引用计数操作,引用计数加1,然后再把它标记为黑色。
第六百三十行的算法的最后一步是D算法遍历删除变量容器根缓冲(zval根),并检查是否有白色标记在前一步变容器,每个容器标有白色的变量被清除。在{ gc_collect_cycles(gc_collect_roots)->()(zval_collect_white)},我们可以看到,白色标记的节点将被添加到全局变量zval_to_free.this列表的列表是有用的后续操作。
PHP的垃圾收集机制在执行过程中被标记为四种颜色。
gc_white白色意味着垃圾
gc_purple紫色表明它已被放置在一个缓冲区
灰色gc_grey表明一个引用计数减操作了
gc_black黑色是默认的颜色,正常
相关的标记和操作代码如下所示:
复制代码代码如下所示:
#定义gc_color 0x03
#定义gc_black 0x00
#定义gc_white 0x01
#定义gc_grey 0x02
#定义gc_purple 0x03
#定义gc_address(V)
((gc_root_buffer *)(((zend_uintptr_t)(v))~ gc_color)))
#定义gc_set_address(V,A)
((V)=(gc_root_buffer *)((((zend_uintptr_t)(v))|(gc_color)(zend_uintptr_t)(一))))
#定义gc_get_color(V)
(((zend_uintptr_t)(v))gc_color)
#定义gc_set_color(V,C)
((V)=(gc_root_buffer *)((((zend_uintptr_t)~ gc_color(V)))|(C)))
#定义gc_set_black(V)
(v)=((gc_root_buffer *)(((zend_uintptr_t)(v))~ gc_color)))
#定义gc_set_purple(V)
((V)=(gc_root_buffer *)(((zend_uintptr_t)gc_purple(V))|))
上面的逐位标记方式在PHP的源代码中很有用,如内存管理等,这是一种高效和经济的解决方案,但是当我们进行数据库设计时,我们可能无法使用这种方法来实现字段。应该以更直观、更易读的方式实现它。
声明:本文内容用于数码产品信息整理与选购参考,具体价格、库存、售后政策以官方渠道和电商页面实时信息为准。