This article mainly introduces the memory overflow instance analysis for mutual reference of PHP Objects, which is a common bug in PHP5.3 and later versions. the solution is provided in this article, for more information, see. generally, one of the biggest advantages of using a scripting language is to use its automatic garbage collection mechanism to release memory. You do not need to release the memory after using the variable, because these PHP will help you.
Of course, we can call the unset () function as needed to release the memory, but this is usually not required.
However, in PHP, memory is not automatically released in at least one case, even when unset () is called manually (). Details can test PHP official website on memory leakage analysis: http://bugs.php.net/bug.php? Id = 33595.
Symptoms:
If there is a mutual reference relationship between the two objects, such as "parent object-sub-object", call unset () for the parent object () the memory of the parent object referenced in the sub-object is not released (even if the parent object is reclaimed by garbage collection ).
Are you confused? Let's take a look at the following code:
<?phpclass Foo { function __construct(){ $this->bar = new Bar($this); }}class Bar { function __construct($foo = null){ $this->foo = $foo; }}while (true) { $foo = new Foo(); unset($foo); echo number_format(memory_get_usage()) . " ";}?>
Run this code and you will see that the memory usage is getting higher and higher until the light is used up.
...33,551,61633,551,97633,552,33633,552,696PHP Fatal error: Allowed memory size of 33554432 bytes exhausted(tried to allocate 16 bytes) in memleak.php on line 17
This is not a problem for most PHP programmers. However, if you use a lot of referenced objects in a long-running code, especially when the object is relatively large, the memory will be quickly exhausted.
Userland solution
Although tedious and not elegant, a solution is provided in the previously mentioned bugs.php.net link.
This solution uses a destructor method before releasing an object to achieve the goal. The Destructor method can clear all internal parent object references, that is, it can release the memory that would have been overflows.
The following is the "fixed" code:
<?phpclass Foo { function __construct(){ $this->bar = new Bar($this); } function __destruct(){ unset($this->bar); }}class Bar { function __construct($foo = null){ $this->foo = $foo; }}while (true) { $foo = new Foo(); $foo->__destruct(); unset($foo); echo number_format(memory_get_usage()) . " ";}?>
Note the newly added Foo ::__ destruct () method and call $ foo->__ destruct () before releasing the object. Now this code solves the problem of increasing memory usage, so that the code can work well.
PHP kernel solution
Why is memory overflow? I am not proficient in PHP kernel research, but it is certain that this problem is related to reference count.
The reference count for referencing $ foo in $ bar will not decrease because the parent object $ foo is released. PHP considers that you still need the $ foo object, so that this part of memory will not be released. The principle is roughly the same.
In general, a reference count is not decreasing, so some memory will never be released.
In addition, in the bugs.php.net link mentioned above, it is pointed out that the process of modifying garbage collection will sacrifice a lot of performance, so you need to pay attention to this.
Instead of changing the garbage collection process, why don't unset () be used to release internal objects? (Or call _ destruct () when releasing an object ()?)
Maybe PHP kernel developers can modify this garbage collection mechanism here or elsewhere.
I believe this article will help you understand the PHP operating principles in depth.