Garbage collection mechanism underlying principle of PHP5

concept

Garbage collection mechanism is a dynamically allocated memory scheme, it will automatically release the allocated memory block of the program is no longer used.

Garbage collection mechanism allows programmers to not be overly concerned about memory allocation program, which put more energy into the business logic.

Associated with a concept, a memory leak means that the program failed to release that memory no longer in use, resulting in a waste of memory.

So PHP garbage collection mechanism is how to achieve it?

Internal storage structure PHP variables

First is the need to understand at the basics , to facilitate an understanding of the principles of the content of the garbage collector.

PHP all types of variables are at the bottom zval structure implementation (source code file Zend / zend.h) in the form of

Source root directory search

grep -rin --color --include=*.h --include=*.c _zval_struct *

struct _zval_struct {
    /* Variable information */
    zvalue_value value;     /* 变量value值 */
    zend_uint refcount__gc; /* 引用计数内存中使用次数,为0删除该变量 */
    zend_uchar type;    /* 变量类型 */
    zend_uchar is_ref__gc; /* 区分是否是引用变量,是引用为1,否则为0 */
};

Note: The above zval structure is a structure after php5.3 version, before php5.3 because there is no introduction of a new garbage collection mechanism, namely GC , so named no _gc; but after php7 version due to performance issues so rewritten zval structure here no longer expressed.

Reference counting principle

Variable container

Each stored in a PHP variable called zval variable container. When creating a variable container, the container variable ref_count initial value 1, to be used after each variable, ref_count + 1 . When you delete a variable ( unset () ), then it points to a variable container ref_count - 1 .

Non-array and object variables

Each time constants assigned to a variable, will have a variable container

For example:

$a = 'new string';
xdebug_debug_zval('a');

The results will be output:

a:(refcount=1, is_ref=0),string 'new string' (length=10)

array and object variables

Each time a variable constant values, will have the number of elements +1 zval

For example:

$b = [
    'name' => 'new string',
    'number' => 12
];
xdebug_debug_zval('b');

The results will be output:

b:
(refcount=1, is_ref=0),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
  'number' => (refcount=1, is_ref=0),int 12

Assignment Principle

Copy-on-write principle

php in the design, in order to save memory, so that the assignment between the variables, for the same values of two variables, a memory is shared, that is, will be in the global symbol table within the variable b of the variable pointers point to a variable point of zval the same structure , but only when zval structure in which a variable changes, will change the variable container memory copy occurs, and therefore is called copy-on-write principle .

Copy-on-write principle  Trigger timing:

php when modifying a variable, the variable is found if refcount> 1, the container will perform variable memory copy

For example:

// 创建一个变量容器,变量 a 指向给变量容器,a 的 ref_count 为 1
$a = ['name' => 'string','number' => 3];    

// 变量 b 也指向变量 a 指向的变量容器,a 和 b 的 ref_count 为 2
$b = $a;    
xdebug_debug_zval('a', 'b');
echo '<hr/>'
// 变量 b 的其中一个元素发生改变,此时会复制出一个新的变量容器,变量 b 重新指向新的变量容器,a 和 b 的ref_count 变成 1
$b['name'] = 'new string';  
xdebug_debug_zval('a', 'b'); 

Output results:

a:(refcount=2, is_ref=0),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'string' (length=6)
  'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=0),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'string' (length=6)
  'number' => (refcount=1, is_ref=0),int 3
________________________________________________________________________________________  
a:(refcount=1, is_ref=0),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'string' (length=6)
  'number' => (refcount=2, is_ref=0),int 3
b:(refcount=1, is_ref=0),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
  'number' => (refcount=2, is_ref=0),int 3

 

Change principle when writing

He says the case of an ordinary assignment, then the assignment will refer to it?

By way of illustration first

$a = ['name' => 'string','number' => 3];    
$b = &$a;
xdebug_debug_zval("a", "b");

The results output

a:(refcount=2, is_ref=1),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'string' (length=6)
  'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=1),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'string' (length=6)
  'number' => (refcount=1, is_ref=0),int 3

At this point, we find the variables a and b refcount or two, but is_ref becomes 1, it is because when a reference variable assigned to the variable b, the variable has been modified in the original container, will become is_ref 1, and refcount + 1

That assignment on the basis of reference if they changed the variables of it?

$a = ['name' => 'string','number' => 3];    
$b = &$a;
$b['name'] = "new string";
xdebug_debug_zval("a", "b");

Output results:

a:(refcount=2, is_ref=1),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
  'number' => (refcount=1, is_ref=0),int 3
b:(refcount=2, is_ref=1),
array (size=2)
  'name' => (refcount=1, is_ref=0),string 'new string' (length=10)
  'number' => (refcount=1, is_ref=0),int 3

Amazing thing happened, there was a change in the value of the variable a variable b and, in fact, because the triggers to change the write principle .

Change the write principle  Trigger timing:
is_ref variable container 1 before being assigned priority check container is_ref variable is equal to 1, if a copy-on-write is not performed, but modified to make the contents of the container on the basis of the original variables; and if the other variables is_ref assigned to the variable container 1, it will immediately trigger a change write principle

Now combine the above examples, it will be like?

$a = ['name' => 'string','number' => 3];    
$b = $a;
$c = &$a;
xdebug_debug_zval("a", "b", "c");

Output results:

Implementation process:

Performing a first row: refcount is a variable container

Performing a second row: refcount variable container 2, the variables a and b share the same variable container

The implementation of the third line: To reference a variable assigned to the variable c, this time variable container refcount> 1, if change is to occur, will trigger copy-on-write , the separation of the variables a and b, then the variable is assigned to a reference C variable, the variable is_rel container becomes 1, and 2 becomes refcount.

Reference count to 0

When the container is variable ref_count count to 0, indicating that the variable container will be destroyed to achieve the memory recovery.

This is the garbage collection prior to PHP 5.3 version.

For example:

$a = "new string";
$b = $a;
xdebug_debug_zval('a');
unset($b);      // 删除了符号表中的变量名 b,同时它指向的变量容器 ref_count -1
xdebug_debug_zval('a');
xdebug_debug_zval('b');

Output results:

a:(refcount=2, is_ref=0),string 'new string' (length=10)
a:(refcount=1, is_ref=0),string 'new string' (length=10)
b: no such symbol

Circular reference memory leaks caused by

When we add an array or object as an element of this array or object, and if this time delete the variable symbol (unset), this variable container will not be deleted. Because of its child elements are still pointing to the variable container, but because of all the scope without any sign pointing to the variable container, so users no way to clear this variable container, the result will lead to memory leaks until the end of script execution passive clear this variable container .

For example: the array as an element to add to your

$a = array( 'one' );
$a[] = &$a;
xdebug_debug_zval( 'a' );

Outputs:

a:
(refcount=2, is_ref=1),
array (size=2)
  0 => (refcount=1, is_ref=0),string 'one' (length=3)
  1 => (refcount=2, is_ref=1),&array<

Icon:

To see the array variable a is also the second element of the array of "1" variable container pointed refcount is 2 . The output of the above & array < means being directed toward the original array.

Just as with the call for a variable unset will remove the symbol, and the number of citations variable container it points is also decreased by one. So, if we are executing the above code, the variable a call unset, then the variable a and variable array elements container pointed to "1" citations subtract 1 from 2 becomes 1 . The following example may illustrate :

unset($a);

Icon:

If the above situation occurs only once or twice down nothing, but if thousands of times, even hundreds of thousands of times a memory leak occurs, which is obviously a big problem. Such problems often occur in the long-running script, such as the request daemon (deamons) basically does not end or large unit test suite (sets) in.

The new garbage collection

PHP 5.3 version introduced after the root buffering mechanism , default settings specified number of root buffer zval i.e. PHP starts (default 10000), it was found when the presence of PHP circular references when the zval, will put its roots into the buffer, when after the root buffer reaches the number specified configuration file (default is 10000), will carry out garbage collection, in order to resolve memory leaks caused by circular references.

Garbage collection algorithm

Whenever the root buffer is full, PHP will buffer the root of all variables vessel traversing be simulated delete , and then simulate recovery . However, PHP will only be deleted after the simulation refcount> 0 of the variable container recovery , then no recovery is refcount = 0 is the garbage of the.

Recognized as a criterion of garbage

1, if the reference count is reduced to zero, where the container variable is cleared (Free), not spam
2, if a reference zval further decrements the count is greater than 0, then it will cycle into the garbage. Next, in a period of garbage, by checking whether the reference count number is decremented by 1, and which container inspection reference variable is zero, to find out which parts are garbage.

to sum up

Garbage collection:
1 to php based on reference counting mechanism (the mechanism previously only PHP5.3)
2, while the root buffer mechanism, when there is a circular php find the zval references, which will put into the root buffer, the buffer when the root reaches the number specified configuration file, it will be garbage collected, in order to resolve memory leaks caused by circular references (php5.3 began to introduce the mechanism)

Reference material

Advanced PHP garbage collection mechanism of learning Detailed

Garbage collection mechanism underlying principle of php

Reference Counting Basics

Guess you like

Origin www.cnblogs.com/wuliaojava/p/11759806.html