PHP garbage collection mechanism

Source: Internet
Author: User
Tags garbage collection memory usage

The garbage collection mechanism used before php 5.3 is a simple "reference count", that is, each memory object is allocated with a counter. When the memory object is referenced by a variable, the counter is + 1; when the variable reference is removed, counter-1; when counter = 0, indicates that the memory object is not used, the memory object is destroyed, and garbage collection is completed.

There is a problem with "reference count", that is, when two or more objects reference each other to form a ring, the counter of the memory object will not be reduced to 0; at this time, this group of memory objects is useless, but cannot be recycled, resulting in memory leakage;

Php5.3 started with a new garbage collection mechanism. Based on reference counting, it implemented a complex algorithm to detect the existence of reference rings in memory objects to avoid memory leakage.

 

The php variable exists in a variable container named "zval". The "zval" variable container includes the variable type and value, and contains two additional bytes, "is_ref" indicates whether the variable is referenced, and "refcount" indicates the number of variables in the zval variable container.

If you have installed xdebug, you can use xdebug_debug_zval () to display "zval" information. As follows:

<? Php
$ Str = "www.111cn.net ";
Xdebug_debug_zval ('str ');


Result:

Str:

(Refcount = 1, is_ref = 0 ),

String 'phpddt. Com' (length = 10)

The variable container is destroyed only when "refcount" is changed to 0. when you unset () a variable, the refcount in the desired "zval" will be reduced by 1. Let's talk about the unset reference problem encountered a few days ago:

 

The code is as follows: Copy code

<? Php
$ A = "aaa ";
$ B = & $;
Unset ($ );
// Echo $ B; // aaa will still be output here. Print it with xdebug_debug_zval and you will know why.
Xdebug_debug_zval ("B ");

 

Result:

B:

(Refcount = 1, is_ref = 0), string 'AAA' (length = 3)

Continue to talk about the reference counter problem. The matching types of array and object are different:

 

The code is as follows: Copy code

<? Php
 
$ Arr = array ('a' => 'AAA', 'B' => "bbb ");
Xdebug_debug_zval ('arr ');
$ Arr ['AAA'] = $ arr ['A'];
Xdebug_debug_zval ('arr ');
?>


Result:

Arr:

(Refcount = 1, is_ref = 0 ),

Array

'A' => (refcount = 1, is_ref = 0), string 'AAA' (length = 3)

'B' => (refcount = 1, is_ref = 0), string 'BBB '(length = 3)

Arr:

(Refcount = 1, is_ref = 0 ),

Array

'A' => (refcount = 2, is_ref = 0), string 'AAA' (length = 3)

'B' => (refcount = 1, is_ref = 0), string 'BBB '(length = 3)

'AAA' => (refcount = 2, is_ref = 0), string 'AAA' (length = 3)


We can see that the original array elements and newly added array elements are associated with the zval variable container of the same "refcount" 2. Here I am only playing a role in attracting others.

Above, we simply used unset, null, mysql_close ,__ destruct, xdebug_debug_zval, and then looked down.


Check for memory leakage

Check whether the released memory is not released. You can simply call the memory_get_usage function to check the memory usage. The memory usage data returned by the memory_get_usage function is not very accurate, you can use the xdebug extension of php to obtain more accurate and detailed memory usage.

The code is as follows: Copy code

Class {
Private $ B;
Function _ construct (){
$ This-> B = new B ($ this );
    }
Function _ destruct (){
// Echo "A destructn ";
    }
}

Class B {
Private $;
Function _ construct ($ ){
$ This-> a = $;
    }
Function _ destruct (){
// Echo "B descturctn ";
    }
}

For ($ I = 0; $ I ++ ){
$ A = new ();
If ($ I % 1000 = 0 ){
Echo memory_get_usage (). "n ";
    }

}

}

The preceding example creates A ring reference. Every time you create instance a of object a, instance B of object B is created, and instance B of object B is referenced by instance a. In this way, every A object is always referenced by a B, and every B object is referenced by an object A at the same time. The reference ring is like this.

When executing this code in the php5.2 environment, we will find that the memory usage increases monotonically, and there is no "A/B desctruct" information output after the destructor A and B are executed; until the memory is exhausted, the output is "PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 40 bytes )".

When you run this code in php5.3, you will find that the memory usage jumps up and down, but it never exceeds the limit. The program will also output A large number of "A/B desctruct ", this indicates that the destructor has been called.

This reference loop exists in my colleague's program, and his script is actually executed under php5.2.3. The simple_html_dom tool has two classes: simple_html_dom and simple_html_dom_node. The former contains a group member variable nodes, and each element in the array is a simple_html_dom_node object; each simple_html_dom_node object has a member variable dom. The dom value is the simple_html_dom object in front. This forms a beautiful reference ring, leading to memory leakage. The solution is also very simple, that is, when the simple_html_dom object is used up, it actively calls its clear function, clears its member variable nodes, the ring is broken, and the memory leakage will not happen.

 


3. Others:

1) garbage collection time


In Php, if the reference count is 0, the memory will be released immediately. That is to say, there is no cyclically referenced variable, and the memory will be immediately released out of the scope of the variable.

Ring reference detection is triggered when certain conditions are met. Therefore, in the above example, we can see that the memory used fluctuates greatly. We can also use the gc_collect_cycles function to actively perform ring reference detection.

2) & symbol impact

Explicitly referencing a variable increases the reference count of the memory:

$ A = "something ";

$ B = & $;

At this time, unset ($ a), but there is still a reference of $ B pointing to the memory area, the memory will not be released.

3) Impact of unset functions

Unset only disconnects a variable from A memory area, and calculates the reference count of the memory area-1. In the preceding example, inside the loop body, $ a = new (); unset ($ a); does not reduce the reference count of $ a to zero;

4) = Impact of null operations;

$ A = null: directly empty the data structure pointed to by $ a and return the reference count to 0.

5) Impact of script execution completion

After the script is executed, all memory used in the script will be released, regardless of whether there is a reference ring.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.