Memory consumption regression in 0.12.83
Bug report
It seems that there is a memory consumption regression in version 0.12.83 caused by this. Phpstan throws the following error when analysing the project:
mmap() failed: [12] Cannot allocate memory
PHP Fatal error: Out of memory (allocated 4665122816) (tried to allocate 4294967304
bytes) in
phar:///___/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeRes
olver.php on line 574
Since that line does $throwPoints = \array_merge($throwPoints, $branchScopeStatementResult->getThrowPoints()); it leads me to believe that it has something to do with the new exception funcionality. However, I do not understand phpstan internals so maybe I'm wrong. But it is definitely strange that it tries to allocate 4 more gigabytes.
Unfortunately, the project is not open source so I can't just link the source code here. But to give you a rough context it's about 5k PHP files with a total of about 600k LoC. I'm running phpstan with php 7.4 in a vagrant VM with 6 GB of RAM (barely enough to analyse the whole project with 0.12.82). (I also tried running it on host with a larger amount of RAM, but it was still not enough: Allowed memory size of 12884901888 bytes exhausted (tried to allocate 8589934600 bytes)). I'm not sure how much it matters but the project is not very well written with respect to @throws. Most of the methods don't have it and if it's there it's mostly just whatever phpstorm complained about. 😄
Perhaps using [$a, $b] instead of array_merge($a, $b) would be better for memory consumption? OFC it's not as nice of a data structure, but if it were to save gigabytes of memory usage it would seem worth it to me. Here is a small PoC with roughly what I suspect is going on:
<?php ini_set('memory_limit', '1G'); $o = (object) []; $node = [$o]; $intermediaryArrays = []; for ($i = 0; $i < 10; $i++) { //$level = array_merge($node, $node, $node, $node, $node); // flat $level = [$node, $node, $node, $node]; // tree $intermediaryArrays[] = $level; $node = $level; } echo number_format(memory_get_usage()) . "\n";
With "flat" it outputs: 626,070,984
With "tree" it outputs: 396,320
Expected output
Memory consumption should be roughly in line with 0.12.82 + a reasonable amount for the new functionality.