search
HomeBackend DevelopmentPHP TutorialA brief discussion on the evolution of the garbage collection algorithm (Garbage Collection) in PHP5_PHP Tutorial

Foreword: PHP is a managed language. In PHP programming, programmers do not need to manually handle the allocation and release of memory resources (except when using C to write PHP or Zend extensions), which means that PHP itself implements The garbage collection mechanism (Garbage Collection) is implemented. Now if you go to the official PHP website (php.net) you can see that the current two branch versions of PHP5, PHP5.2 and PHP5.3, are updated separately. This is because many projects still use the 5.2 version of PHP, and the 5.3 version is 5.2 is not fully compatible. PHP5.3 has made many improvements based on PHP5.2, among which the garbage collection algorithm is a relatively big change. This article will discuss the garbage collection mechanisms of PHP5.2 and PHP5.3 respectively, and discuss the impact of this evolution and improvement on programmers writing PHP and the issues they should pay attention to.

Internal representation of PHP variables and associated memory objects

In the final analysis, garbage collection is the operation of variables and their associated memory objects, so before discussing PHP’s garbage collection mechanism, let’s briefly introduce the internal representation of variables and their memory objects in PHP (its representation in the C source code ).

The official PHP documentation divides variables in PHP into two categories: scalar types and complex types. Scalar types include booleans, integers, floating point types and strings; complex types include arrays, objects and resources; there is also a special NULL, which is not divided into any type, but becomes a separate category.

All these types are uniformly represented by a structure called zval within PHP. In the PHP source code, the name of this structure is "_zval_struct". The specific definition of zval is in the "Zend/zend.h" file of the PHP source code. The following is an excerpt of the relevant code.

 

typedef union _zvalue_value {
	long lval;					/* long value */
	double dval;				/* double value */
	struct {
		char *val;
		int len;
	} str;
	HashTable *ht;				/* hash table value */
	zend_object_value obj;
} zvalue_value;

struct _zval_struct {
	/* Variable information */
	zvalue_value value;		/* value */
	zend_uint refcount__gc;
	zend_uchar type;	/* active type */
	zend_uchar is_ref__gc;
};

The union "_zvalue_value" is used to represent the values ​​of all variables in PHP. The reason why union is used here is because a zval can only represent one type of variable at a time. You can see that there are only 5 fields in _zvalue_value, but there are 8 data types in PHP including NULL. So how does PHP use 5 fields to represent 8 types internally? This is one of the more clever aspects of PHP design. It achieves the purpose of reducing fields by reusing fields. For example, within PHP, Boolean types, integers and resources (as long as the identifier of the resource is stored) are stored through the lval field; dval is used to store floating point types; str stores strings; ht stores arrays (note that in PHP The array is actually a hash table); and obj stores the object type; if all fields are set to 0 or NULL, it means NULL in PHP, so that 5 fields are used to store 8 types of values.

What type the value in the current zval (the type of value is _zvalue_value) represents is determined by the type in "_zval_struct". _zval_struct is the specific implementation of zval in C language. Each zval represents a memory object of a variable. In addition to value and type, you can see that there are two fields refcount__gc and is_ref__gc in _zval_struct. From their suffixes, you can conclude that these two guys are related to garbage collection. That's right, PHP's garbage collection relies entirely on these two fields. Among them, refcount__gc indicates that there are several variables currently referencing this zval, and is_ref__gc indicates whether the current zval is referenced by reference. This sounds very confusing. This is related to the "Write-On-Copy" mechanism of zval in PHP. Since this topic is not This article is the focus, so I won’t go into details here. Readers only need to remember the role of the refcount__gc field.

Garbage collection algorithm in PHP5.2——Reference Counting

The memory recycling algorithm used in PHP5.2 is the famous Reference Counting. The Chinese translation of this algorithm is called "reference counting". Its idea is very intuitive and concise: assign a counter to each memory object. When a memory object is created The counter is initialized to 1 (so there is always a variable referencing this object at this time). Every time a new variable refers to this memory object, the counter increases by 1, and every time a variable that references this memory object is reduced, the counter decreases by 1. When the garbage collection mechanism operates, all memory objects with a counter of 0 are destroyed and the memory they occupy is reclaimed. The memory object in PHP is zval, and the counter is refcount__gc.

For example, the following piece of PHP code demonstrates the working principle of the PHP5.2 counter (the counter value is obtained through xdebug.org):


$val1 = 100; //zval(val1).refcount_gc = 1;
$val2 = $val1; //zval(val1).refcount_gc = 2,zval(val2).refcount_gc = 2(因为是Write on copy,当前val2与val1共同引用一个zval)
$val2 = 200; //zval(val1).refcount_gc = 1,zval(val2).refcount_gc = 1(此处val2新建了一个zval)
unset($val1); //zval(val1).refcount_gc = 0($val1引用的zval再也不可用,会被GC回收)

?>


$val1 = 100; //zval(val1).refcount_gc = 1;
$val2 = $val1; //zval(val1).refcount_gc = 2,zval(val2).refcount_gc = 2 (because it is Write on copy, currently val2 and val1 jointly reference a zval)
$val2 = 200; //zval(val1).refcount_gc = 1,zval(val2).refcount_gc = 1 (val2 creates a new zval here)
unset($val1); //zval(val1).refcount_gc = 0 (the zval referenced by $val1 is no longer available and will be recycled by GC)

?>

Reference Counting is simple, intuitive, and easy to implement, but it has a fatal flaw, which is that it can easily cause memory leaks. Many friends may have realized that if there is a circular reference, Reference Counting may cause memory leaks. For example, the following code:


$a = array();
$a[] = & $a;
unset($a);

?>


$a = array();
$a[] ​​= & $a;
unset($a);

?>

This code first creates the array a, and then lets the first element of a point to a by reference. At this time, the refcount of zval of a becomes 2. Then we destroy the variable a. At this time, the zval that a initially points to The refcount is 1, but we can no longer operate on it because it forms a circular self-reference, as shown in the figure below:

A brief discussion on the evolution of the garbage collection algorithm (Garbage Collection) in PHP5_PHP Tutorial

The gray part means it no longer exists. Since the refcount of the zval pointed to by a is 1 (referenced by the first element of its HashTable), this zval will not be destroyed by GC, and this part of the memory will be leaked.

What is particularly important to point out here is that PHP stores variable symbols through a symbol table (Symbol Table). There is a global symbol table, and each complex type such as an array or object has its own symbol table. Therefore, in the above code, a and a[0] are two symbols, but a is stored in the global symbol table, and a[0] is stored in the symbol table of the array itself, and here a and a[0] refer to the same zval (of course the symbol a was later destroyed). I hope readers will pay attention to distinguishing the relationship between symbol (Symbol) and zval.

When PHP is only used for dynamic page scripts, this leakage may not be very important, because the life cycle of dynamic page scripts is very short, and PHP will ensure that all its resources are released when the script is executed. However, PHP has developed to the point where it is no longer just used as a dynamic page script. If PHP is used in scenarios with a long life cycle, such as automated test scripts or deamon processes, the memory leaks accumulated after many cycles may be It will be serious. This is not sensational. A company I once interned with used a deamon process written in PHP to interact with the data storage server.

Due to this flaw in Reference Counting, PHP5.3 improved the garbage collection algorithm.

Garbage collection algorithm in PHP5.3 - Concurrent Cycle Collection in Reference Counted Systems

The garbage collection algorithm of PHP5.3 is still based on reference counting, but it no longer uses simple counting as the recycling criterion, but uses a synchronous recycling algorithm. This algorithm was proposed by IBM engineers in the paper Concurrent Cycle Collection in Reference Counted Systems.

This algorithm is quite complex. I think everyone can tell from the 29 pages of the paper, so I do not intend (and do not have the ability) to fully discuss this algorithm. Interested friends can read the paper mentioned above ( Highly recommended, the paper is brilliant).

I can only briefly describe the basic idea of ​​this algorithm here.

First, PHP will allocate a fixed-size "root buffer". This buffer is used to store a fixed number of zvals. The default number is 10,000. If you need to modify it, you need to modify the source code Zend/zend_gc.c The constant GC_ROOT_BUFFER_MAX_ENTRIES and then recompile.

From the above we can know that if a zval has a reference, it will either be referenced by a symbol in the global symbol table or by a symbol in other zvals that represent complex types. So there are some possible roots in zval. Here we will not discuss how PHP discovers these possible roots. This is a very complex problem. In short, PHP has a way to discover these possible root zvals and put them into the root buffer.

When the root buffer is full, PHP will perform garbage collection. The recycling algorithm is as follows:

1. For the root zval in each root buffer, traverse all zvals that can be traversed according to the depth-first traversal algorithm, and decrement the refcount of each zval by 1. At the same time, in order to avoid decrementing the same zval by 1 multiple times (because Different roots may traverse the same zval). Each time a zval is decremented by 1, it is marked as "decremented".

2. Traverse the root zval in each buffer depth-first again. If the refcount of a zval is not 0, add 1 to it, otherwise keep it at 0.

3. Clear all roots in the root buffer (note that these zvals are cleared from the buffer instead of destroying them), then destroy all zvals with a refcount of 0, and reclaim their memory.

It’s okay if you don’t fully understand it. Just remember that the garbage collection algorithm of PHP5.3 has the following characteristics:

1. The recycling cycle does not start every time the refcount decreases. Garbage collection only starts after the root buffer is full.

2. Can solve the circular reference problem.

3. Memory leaks can always be kept below a threshold.

Performance comparison of garbage collection algorithms between PHP5.2 and PHP5.3

Due to my current limitations, I will not redesign the experiment, but directly quote the experiment in the PHP Manual. For a performance comparison between the two, please refer to the relevant chapters in the PHP Manual: http://www.php .net/manual/en/features.gc.performance-considerations.php.

The first is the memory leak test. The experimental code and test result diagram in the PHP Manual are directly quoted below:

class Foo
{
    public $var = '3.1415962654';
}

$baseMemory = memory_get_usage();

for ( $i = 0; $i {
    $a = new Foo;
    $a->self = $a;
    if ( $i % 500 === 0 )
    {
        echo sprintf( '%8d: ', $i ), memory_get_usage() - $baseMemory, "n";
    }
}
?>

class Foo
{
    public $var = '3.1415962654';
}

$baseMemory = memory_get_usage();

for ( $i = 0; $i {
    $a = new Foo;
    $a->self = $a;
    if ( $i % 500 === 0 )
    {
        echo sprintf( '%8d: ', $i ), memory_get_usage() - $baseMemory, "n";
    }
}
?>

A brief discussion on the evolution of the garbage collection algorithm (Garbage Collection) in PHP5_PHP Tutorial

可以看到在可能引发累积性内存泄露的场景下,PHP5.2发生持续累积性内存泄露,而PHP5.3则总能将内存泄露控制在一个阈值以下(与根缓冲区大小有关)。

另外是关于性能方面的对比:

class Foo
{
    public $var = '3.1415962654';
}

for ( $i = 0; $i {
    $a = new Foo;
    $a->self = $a;
}

echo memory_get_peak_usage(), "n";
?>

class Foo
{
    public $var = '3.1415962654';
}

for ( $i = 0; $i {
    $a = new Foo;
    $a->self = $a;
}

echo memory_get_peak_usage(), "n";
?>

这个脚本执行1000000次循环,使得延迟时间足够进行对比,然后使用CLI方式分别在打开内存回收和关闭内存回收的的情况下运行此脚本:

time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
# and
time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php

time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
# and
time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php

在我的机器环境下,运行时间分别为6.4s和7.2s,可以看到PHP5.3的垃圾回收机制会慢一些,但是影响并不大。

与垃圾回收算法相关的PHP配置

可以通过修改php.ini中的zend.enable_gc来打开或关闭PHP的垃圾回收机制,也可以通过调用gc_enable( )或gc_disable( )打开或关闭PHP的垃圾回收机制。在PHP5.3中即使关闭了垃圾回收机制,PHP仍然会记录可能根到根缓冲区,只是当根缓冲区满额时,PHP不会自动运行垃圾回收,当然,任何时候您都可以通过手工调用gc_collect_cycles( )函数强制执行内存回收。

本文基于署名-非商业性使用 3.0许可协议发布,欢迎转载,演绎,但是必须保留本文的署名张洋

(包含链接),且不得用户商业目的。

http://www.bkjia.com/PHPjc/371631.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/371631.htmlTechArticle
前言:PHP是一门托管型语言,在PHP编程中程序员不需要手工处理内存资源的分配与释放(使用C编写PHP或Zend扩展除外),这就意味着PHP本身...
Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
php5和php8有什么区别php5和php8有什么区别Sep 25, 2023 pm 01:34 PM

php5和php8的区别在性能、语言结构、类型系统、错误处理、异步编程、标准库函数和安全性等方面。详细介绍:1、性能提升,PHP8相对于PHP5来说在性能方面有了巨大的提升,PHP8引入了JIT编译器,可以对一些高频执行的代码进行编译和优化,从而提高运行速度;2、语言结构改进,PHP8引入了一些新的语言结构和功能,PHP8支持命名参数,允许开发者通过参数名而不是参数顺序等等。

基于因果森林算法的决策定位应用基于因果森林算法的决策定位应用Apr 08, 2023 am 11:21 AM

译者 | 朱先忠​审校 | 孙淑娟​在我之前的​​博客​​中,我们已经了解了如何使用因果树来评估政策的异质处理效应。如果你还没有阅读过,我建议你在阅读本文前先读一遍,因为我们在本文中认为你已经了解了此文中的部分与本文相关的内容。为什么是异质处理效应(HTE:heterogenous treatment effects)呢?首先,对异质处理效应的估计允许我们根据它们的预期结果(疾病、公司收入、客户满意度等)选择提供处理(药物、广告、产品等)的用户(患者、用户、客户等)。换句话说,估计HTE有助于我

Mango:基于Python环境的贝叶斯优化新方法Mango:基于Python环境的贝叶斯优化新方法Apr 08, 2023 pm 12:44 PM

译者 | 朱先忠审校 | 孙淑娟引言模型超参数(或模型设置)的优化可能是训练机器学习算法中最重要的一步,因为它可以找到最小化模型损失函数的最佳参数。这一步对于构建不易过拟合的泛化模型也是必不可少的。优化模型超参数的最著名技术是穷举网格搜索和随机网格搜索。在第一种方法中,搜索空间被定义为跨越每个模型超参数的域的网格。通过在网格的每个点上训练模型来获得最优超参数。尽管网格搜索非常容易实现,但它在计算上变得昂贵,尤其是当要优化的变量数量很大时。另一方面,随机网格搜索是一种更快的优化方法,可以提供更好的

使用Pytorch实现对比学习SimCLR 进行自监督预训练使用Pytorch实现对比学习SimCLR 进行自监督预训练Apr 10, 2023 pm 02:11 PM

SimCLR(Simple Framework for Contrastive Learning of Representations)是一种学习图像表示的自监督技术。 与传统的监督学习方法不同,SimCLR 不依赖标记数据来学习有用的表示。 它利用对比学习框架来学习一组有用的特征,这些特征可以从未标记的图像中捕获高级语义信息。SimCLR 已被证明在各种图像分类基准上优于最先进的无监督学习方法。 并且它学习到的表示可以很容易地转移到下游任务,例如对象检测、语义分割和小样本学习,只需在较小的标记

​盒马供应链算法实战​盒马供应链算法实战Apr 10, 2023 pm 09:11 PM

一、盒马供应链介绍1、盒马商业模式盒马是一个技术创新的公司,更是一个消费驱动的公司,回归消费者价值:买的到、买的好、买的方便、买的放心、买的开心。盒马包含盒马鲜生、X 会员店、盒马超云、盒马邻里等多种业务模式,其中最核心的商业模式是线上线下一体化,最快 30 分钟到家的 O2O(即盒马鲜生)模式。2、盒马经营品类介绍盒马精选全球品质商品,追求极致新鲜;结合品类特点和消费者购物体验预期,为不同品类选择最为高效的经营模式。盒马生鲜的销售占比达 60%~70%,是最核心的品类,该品类的特点是用户预期时

php5如何改80端口php5如何改80端口Jul 24, 2023 pm 04:57 PM

php5改80端口的方法:1、编辑Apache服务器的配置文件中的端口号;2、辑PHP的配置文件以确保PHP在新端口上工作;3、重启Apache服务器,PHP应用程序将开始在新的端口上运行。

研究表明强化学习模型容易受到成员推理攻击研究表明强化学习模型容易受到成员推理攻击Apr 09, 2023 pm 08:01 PM

​译者 | 李睿 审校 | 孙淑娟​随着机器学习成为人们每天都在使用的很多应用程序的一部分,人们越来越关注如何识别和解决机器学习模型的安全和隐私方面的威胁。 然而,不同机器学习范式面临的安全威胁各不相同,机器学习安全的某些领域仍未得到充分研究。尤其是强化学习算法的安全性近年来并未受到太多关注。 加拿大的麦吉尔大学、机器学习实验室(MILA)和滑铁卢大学的研究人员开展了一项新研究,主要侧重于深度强化学习算法的隐私威胁。研究人员提出了一个框架,用于测试强化学习模型对成员推理攻击的脆弱性。 研究

数据科学家必须了解的六大聚类算法数据科学家必须了解的六大聚类算法Apr 08, 2023 pm 11:31 PM

目前如谷歌新闻等很多应用都将聚类算法作为主要的实现手段,它们能利用大量的未标注数据构建强大的主题聚类。本文从最基础的 K 均值聚类到基于密度的强大方法介绍了 6 类主流方法,它们各有擅长领域与情景,且基本思想并不一定限于聚类方法。本文将从简单高效的 K 均值聚类开始,依次介绍均值漂移聚类、基于密度的聚类、利用高斯混合和最大期望方法聚类、层次聚类和适用于结构化数据的图团体检测。我们不仅会分析基本的实现概念,同时还会给出每种算法的优缺点以明确实际的应用场景。聚类是一种包括数据点分组的机器学习技术。给

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment

VSCode Windows 64-bit Download

VSCode Windows 64-bit Download

A free and powerful IDE editor launched by Microsoft

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),