Home >Backend Development >PHP Tutorial >Detailed explanation of PHP's garbage collection mechanism_PHP tutorial

Detailed explanation of PHP's garbage collection mechanism_PHP tutorial

WBOY
WBOYOriginal
2016-07-13 10:10:071045browse

Detailed explanation of PHP’s garbage collection mechanism

Recently, I wrote a script using PHP to simulate the implementation of a daemon process, so I need to have an in-depth understanding of the garbage collection mechanism in PHP. This article refers to the PHP manual.
Before understanding the PHP garbage collection mechanism (GC), first understand the storage of variables.
Variables in PHP exist in a zval variable container. The structure is as follows:
Type
Value
is_ref
refcount
In zval, in addition to storing the type and value of the variable, there are also is_ref fields and refcount fields.
is_ref: It is a bool value, used to distinguish whether the variable belongs to the reference set. What does it mean? You can think of it this way: indicating whether the variable has more than one alias.
refcount: Counter, indicating the number of variables pointing to this zval variable container.
There is a default relationship between the two: when the refcount value is 1, the value of is_ref is false. Because refcount is 1, this variable cannot have multiple aliases, so there is no reference.
After installing the xdebug extension, you can use xdebug_debug_zval to print out the zval container details.
One thing to note here is that when assigning a variable = to another variable, memory space will not be allocated immediately for the new variable, but 1 will be added to the refcount in the zval of the original variable. Only when the original variable changes, memory space will be allocated for the new variable, and the refcount of the original variable will be reduced by 1. Of course, if you unset the original variable, the new variable directly uses the zval of the original variable instead of reallocating it.
When & is assigned by reference, the is_ref of the original variable becomes 1, and the refcount is increased by 1. If a variable & is assigned a value, the variable previously assigned with = will allocate space.
$a = 1;
xdebug_debug_zval('a');
echo PHP_EOL;
$b = $a;
xdebug_debug_zval('a');
echo PHP_EOL;
$c = &$a;
xdebug_debug_zval('a');
echo PHP_EOL;
xdebug_debug_zval('b');
echo PHP_EOL;
?>
The running results are as follows:
a:(refcount=1, is_ref=0),int 1
a:(refcount=2, is_ref=0),int 1
a:(refcount=2, is_ref=1),int 1
b:(refcount=1, is_ref=0),int 1
The zval described above stores scalars, so how are composite type arrays stored?
$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
echo PHP_EOL;
class Test{
public $a = 1;
public $b = 2;
function handle(){
echo 'hehe';
}
}
$test = new Test();
xdebug_debug_zval('test');
?>
The running results are as follows:
a:(refcount=1, is_ref=0),
array
'meaning' => (refcount=1, is_ref=0),
string
'life' (length=4)
'number' => (refcount=1, is_ref=0),
int
42
test:(refcount=1, is_ref=0),
object(Test)[1]
public 'a' => (refcount=2, is_ref=0),
int
1
public 'b' => (refcount=2, is_ref=0),
int
2
It can be seen that the array uses 1 more zval storage than the array length. Objects are similar. The storage representation of the array is given below
You can see: the array is allocated three zval containers: a meaning number
Now let’s see how the so-called circular reference is generated
$a = array( 'one' );
$a[] =& $a;
xdebug_debug_zval( 'a' );
?>
Running results:
a:(refcount=2, is_ref=1),
array
0 => (refcount=1, is_ref=0),
string
'one' (length=3)
1 => (refcount=2, is_ref=1), &array
The zval container of a and 1 are the same. As follows:
This forms a circular reference.
In PHP 5.2 and earlier versions, there is no dedicated garbage collector GC (Garbage Collection). When the engine determines whether a variable space can be released, it relies on the value of the refcount of the variable's zval. If refcount If it is 0, then the variable space can be released, otherwise it will not be released. This is a very simple GC implementation.
Now unset ($a), then the refcount of the array is reduced by 1 and becomes 1. Now there is no variable pointing to this zval, and the counter of this zval is 1 and will not be recycled.
Although there is no longer any symbol in a scope pointing to this structure (that is, the variable container), since the array element "1" still points to the array itself, this container cannot be cleared. Since there is no other symbol pointing to it, the user has no way to clear the structure, resulting in a memory leak. Fortunately, PHP will clear this data structure at the end of the request, but before PHP clears it, it will consume a lot of space in memory. This happens a lot if you're implementing a parsing algorithm, or doing other things like having a child element point to its parent. Of course, the same situation can happen with objects, in fact it is more likely to happen with objects, because objects are always implicitly referenced.
It’s okay if the above situation occurs only once or twice, but if memory leaks occur thousands or even hundreds of thousands of times, this is obviously a big problem. Problems can arise when running long-running scripts, such as daemons that rarely end when requesting them, and memory space will continue to be consumed, leading to out-of-memory crashes.
In PHP5.3, a special algorithm (more complex) is used. , to deal with the problem of memory leaks caused by circular references.
When a zval may be garbage, the collection algorithm will put the zval into a memory buffer. When the buffer reaches the maximum critical value (the maximum value can be set), the recycling algorithm will cycle through all zvals in the buffer to determine whether they are garbage and perform release processing. Or we use gc_collect_cycles in the script to force the garbage in the buffer to be recycled.
In the GC of php5.3, the garbage is explained as follows:
1: If the refcount of a zval increases, then this zval is still in use, it is definitely not garbage and will not enter the buffer
2: If the refcount of a zval is reduced to 0, then the zval will be released immediately. It is not a garbage object to be processed by the GC and will not enter the buffer.
3: If the refcount of a zval is greater than 0 after being reduced, then the zval cannot be released, and the zval may become garbage and be put into the buffer. The GC in PHP5.3 targets this kind of zval processing.
Turning on/off the garbage collection mechanism can be achieved by modifying the PHP configuration, or it can be turned on and off in the program using gc_enable() and gc_disable().
After turning on the garbage collection mechanism, a large amount of memory space can be saved in case of memory leaks. However, since the garbage collection algorithm takes time to run, turning on the garbage collection algorithm will increase the execution time of the script.
The following is a script given in the php manual
class Foo
{
public $var = '3.1415962654';
}
$baseMemory = memory_get_usage();
for ( $i = 0; $i <= 100000; $i++ )
{
$a = new Foo;
$a->self = $a;
if ( $i % 500 === 0 )
{
echo sprintf( '%8d: ', $i ), memory_get_usage() - $baseMemory, "n";
}
}
?>
 
For this script, its memory usage in php5.2 and 5.3 is given, as shown below:
For the following script
class Foo
{
public $var = '3.1415962654';
}
for ( $i = 0; $i <= 1000000; $i++ )
{
$a = new Foo;
$a->self = $a;
}
echo memory_get_peak_usage(), "n";
?>
 
When the garbage collection mechanism is turned on, the script execution time increases by 7% compared to when it is not turned on
Usually, the garbage collection mechanism in PHP only increases the time consumption when the recycling algorithm is actually running. But in normal (smaller) scripts there should be no performance impact at all.

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/938943.htmlTechArticleDetailed explanation of PHP’s garbage collection mechanism. Recently, I wrote a script using php to simulate the implementation of a daemon process, so I need In-depth understanding of the garbage collection mechanism in PHP. This article refers to...
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