Description
Description
This has mystified me for quite some time.
In PocketMine-MP, we process and cache many simple, acyclic objects like Vector3. When these objects are unref'd (but not destroyed, as they're cached), this causes the object to land in the GC root buffer, despite the object having 0 GC-able children. This causes a couple of problems:
- GC (initially) runs more frequently because the root buffer fills up with non-cyclic objects
- GC runs get less frequent (because the GC threshold increases), but pause for longer, because GC time appears to scale with root buffer size, not the number of cycles.
Since these objects are clearly acyclic, it's just wasting CPU time.
My question in a nutshell
Is there a technical reason why objects with no collectable children are included in the GC root buffer? Any object without array
or object
properties should be able to be ignored, shouldn't it?
Demo code
Here's a test script to demonstrate what I mean.
The V3
class in this sample clearly cannot contain any reference cycles as it only references float
. You can see that the GC time scales according to the size of the root buffer full of these acyclic objects.
final class V3{
public function __construct(
public float $x,
public float $y,
public float $z
){}
}
$array = [];
$gcTime = 0;
while(true){
$lastCollectorTime = gc_status()["collector_time"];
$runs = gc_status()["runs"];
foreach($array as $v3){
//object goes back into gc root buffer
}
for($i = 0; $i < 10001; $i++){
$array[] = new V3(0, 0, 0);
}
$newRuns = gc_status()["runs"];
if($newRuns > $runs){
$gcTime = (gc_status()["collector_time"] - $lastCollectorTime) * 1_000_000_000;
echo "Auto GC has now run $newRuns times, last run took " . number_format($gcTime) . "ns (" . ($gcTime / count($array)) . " ns/object) with " . count($array) . " acyclic objects\n";
}
sleep(1);
}
Example output:
Auto GC has now run 1 times, last run took 156,700ns (15.668433156684 ns/object) with 10001 acyclic objects
Auto GC has now run 2 times, last run took 352,400ns (17.618238176182 ns/object) with 20002 acyclic objects
Auto GC has now run 3 times, last run took 507,800ns (16.92497416925 ns/object) with 30003 acyclic objects
Auto GC has now run 4 times, last run took 786,400ns (19.65803419658 ns/object) with 40004 acyclic objects
Auto GC has now run 5 times, last run took 1,265,900ns (25.315468453155 ns/object) with 50005 acyclic objects
Auto GC has now run 6 times, last run took 1,161,700ns (19.359730693597 ns/object) with 60006 acyclic objects
Auto GC has now run 7 times, last run took 1,483,800ns (21.195023354807 ns/object) with 70007 acyclic objects
Auto GC has now run 8 times, last run took 1,481,700ns (18.519398060194 ns/object) with 80008 acyclic objects
Auto GC has now run 9 times, last run took 1,826,400ns (20.291304202913 ns/object) with 90009 acyclic objects
Auto GC has now run 10 times, last run took 2,648,300ns (26.480351964804 ns/object) with 100010 acyclic objects
Auto GC has now run 11 times, last run took 2,453,100ns (22.298679222987 ns/object) with 110011 acyclic objects
Auto GC has now run 12 times, last run took 3,073,000ns (25.605772756058 ns/object) with 120012 acyclic objects
Auto GC has now run 13 times, last run took 3,423,200ns (26.329674724835 ns/object) with 130013 acyclic objects
Auto GC has now run 14 times, last run took 3,467,300ns (24.763952176211 ns/object) with 140014 acyclic objects
Auto GC has now run 15 times, last run took 3,573,900ns (23.823617638236 ns/object) with 150015 acyclic objects
Auto GC has now run 16 times, last run took 2,809,800ns (17.559494050595 ns/object) with 160016 acyclic objects
Auto GC has now run 17 times, last run took 3,289,700ns (19.349241546434 ns/object) with 170017 acyclic objects
Auto GC has now run 18 times, last run took 3,098,500ns (17.212167672122 ns/object) with 180018 acyclic objects
PHP Version
8.3.13
Operating System
Windows