What gc_collect_cycles function is useful for?

2019-02-02 13:43发布

问题:

Can someone please explain under what circumstances gc_collect_cycles function can be useful? Should it be called before a substantial memory utilization is about to take place?

回答1:

PHP has "Garbage Collector" enabled by default. It is used to free memory used by "garbage". gc_collect_cycles() forces collection of any existing garbage cycles. It returns number of collected (freed) cycles (objects, variable values ...). Enabled Garbage Collector calls this function internally from time to time to free resources. In most cases PHP script lives very short time. In this case all garbage will be destroyed in the end of work without any garbage collection.

Sometimes it's needed to manage GC manually:

  1. gc_disable() can speed up some long operations, but also results in some memory overheads.
  2. gc_collect_cycles() could be used to specify the right moments of GC.

Another one reason to use gc_collect_cycles() - debugging. Assume, you want to know what is the memory consumption of some block of code with memory_get_usage(). You need to disable GC first, elsewhere you'll get wrong results. After that you want to separate the time consumed by GC and by your application. So call gc_collect_cycles() and measure timings/memory before and after.

Little example:

class A {
  public $ref;
  public $name;

  public function __construct($name) {
    $this->name = $name;
    echo($this->name.'->__construct();'.PHP_EOL);
  }

  public function __destruct() {
    echo($this->name.'->__destruct();'.PHP_EOL);
  }
}

gc_disable();

$a1 = new A('$a1');
$a2 = new A('$a2');

$a1->ref = $a2;
$a2->ref = $a1;

$b = new A('$b');
$b->ref = $a1;

echo('$a1 = $a2 = $b = NULL;'.PHP_EOL);
$a1 = $a2 = $b = NULL;
echo('gc_collect_cycles();'.PHP_EOL);
echo('// removed cycles: '.gc_collect_cycles().PHP_EOL);
echo('exit();'.PHP_EOL);

Will output:

$a1->__construct();
$a2->__construct();
$b->__construct();
$a1 = $a2 => $b = NULL;
$b->__destruct();
gc_collect_cycles();
$a2->__destruct();
$a1->__destruct();
// removed cycles: 4

This means that only $b was destroyed when it was asked. Other $a1 and $a2 has cyclic references, and it's name properties also consume memory. Two objects + two strings = 4 (removed by gc_collect_cycles()).