Can I run PHP garbage collection automatically if I have circular links?

I seem to recall a way to configure __destruct for a class in such a way as to ensure that circular references are cleared as soon as the external object falls out of scope. However, the simple test that I built seems to indicate that this does not behave as I expected / hoped.

Is there a way to set up my classes so that PHP clears them correctly when an external object falls out of scope?

I am not looking for alternative ways of writing this code, I am looking for whether this can be done, and if so, how? I usually try to avoid these types of circular references, if possible.

 class Bar { private $foo; public function __construct($foo) { $this->foo = $foo; } public function __destruct() { print "[destroying bar]\n"; unset($this->foo); } } class Foo { private $bar; public function __construct() { $this->bar = new Bar($this); } public function __destruct() { print "[destroying foo]\n"; unset($this->bar); } } function testGarbageCollection() { $foo = new Foo(); } for ( $i = 0; $i < 25; $i++ ) { echo memory_get_usage() . "\n"; testGarbageCollection(); } 

The result is as follows:

 60440 61504 62036 62564 63092 63620 [ destroying foo ] [ destroying bar ] [ destroying foo ] [ destroying bar ] [ destroying foo ] [ destroying bar ] [ destroying foo ] [ destroying bar ] [ destroying foo ] [ destroying bar ] 

What I was hoping for:

 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 60440 [ destorying foo ] [ destorying bar ] 

UPDATE:

There are some great answers to this question regarding PHP> 5.3, but I chose an answer that will work with PHP <5.3 since it really applies to my project (PHP 5.2.x).

+1
source share
4 answers

Since __destruct is called only after restoring an object, you cannot use it for this. You can create a manual cleaning function, but:

 class Foo { private $bar; public function __construct() { $this->bar = new Bar($this); } public function cleanup() { $this->bar = null; } public function __destruct() { print "[destroying foo]\n"; } } class Bar { private $foo; public function __construct($foo) { $this->foo = $foo; } public function __destruct() { print "[destroying bar]\n"; } } function testGarbageCollection() { $foo = new Foo(); $foo->cleanup(); } 

I'm not sure how useful this is, but this is really your only option <5.3

+2
source

The solution could be with PHP> = 5.3 to use what is described in the Garbage Collection section of the manual.

In particular, gc_ * functions may be of interest - see gc_collect_cycles , among others.


In the case of the part of the code you posted with PHP> = 5.3:

  • garbage collection should work
  • BUT it will be launched only when PHP thinks it is necessary !

The second point is very important: since your code is short, it does not require a lot of memory; which means that garbage collection will not be performed at the end of each iteration of the loop:

  • Ok, that will free some memory
  • But this is not necessary, since in any case a lot of memory remains

And since garbage collection takes time, PHP does not run it too often.


Some time ago I wrote an article about my blog where I conducted several tests; this is in French, but the graph (there is no language barrier) in this section clearly shows that the garbage collector runs once in a while, if necessary.

+3
source

http://docs.php.net/features.gc.collecting-cycles :

When the garbage collector is turned on, the loop search algorithm, as described above, is executed whenever the root buffer is full. The root buffer has a fixed size of 10,000 possible roots (although you can change this by changing the constant GC_ROOT_BUFFER_MAX_ENTRIES to Zend / zend_gc.c in the PHP source code and recompiling PHP). When the garbage collector shuts down, the loop search algorithm will never work. However, possible roots will always be written to the root buffer, regardless of whether the garbage collection mechanism has been activated with this configuration setting.

http://docs.php.net/features.gc.performance-considerations :

First of all, the whole reason for introducing the garbage collection mechanism is to reduce memory usage by clearing variables with a circular reference as soon as the necessary conditions are met. In a PHP implementation, this happens as soon as the root buffer is full , or when the gc_collect_cycles () function is called.
+2
source

Starting from 5.3 you can

0
source

Source: https://habr.com/ru/post/1495914/


All Articles