You have written a php script. Generally, you do not need to consider the memory leakage and garbage collection issues, because your script will soon be executed and exited.
However, when the program runs for a period of time and the data volume is large, the php script occupies too much memory and reports an error (PHP Fatal error: allowed memory size of 134217728 bytes exhausted) exited. In general, when the processing of each page ends, the new simple_html_dom object should be destroyed-but it does not actually exist. Obviously, memory leakage occurs.
Garbage collection mechanism of PHP
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.
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.
class A{ private $b; function __construct(){ $this->b = new B($this); } function __destruct(){ //echo "A destruct\n"; }}class B{ private $a; function __construct($a){ $this->a = $a; } function __destruct(){ //echo "B descturct\n"; }}for($i=0;;$i++){ $a = new A(); if($i00 == 0){ echo memory_get_usage()."\n"; }}
The preceding example creates a ring reference. Every time you create instance A of object a, a creates instance B of object B and allows B to reference. In this way, each A object is always referenced by a B, and each B object is referenced by an object A at the same time, so the reference ring is generated.
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 )".
If you run this code in the php5.3 environment, 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", which 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.
Others
1. Garbage Collection Time
In PHP, if the reference count is 0, the memory is immediately released. That is to say, there is no variable referenced in the loop, and the memory is immediately released out of the scope of the variable. The ring reference detection is triggered when certain conditions are met. Therefore, in the above example, we can see that the memory usage fluctuates greatly. You 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 = &$a;
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. = effect of the null operation;
$ 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.