Bug #69639 [NEW]: Closure causes memory leak (Cyclic reference) when used as class property

From: Date: Fri, 15 May 2015 10:15:26 +0000
Subject: Bug #69639 [NEW]: Closure causes memory leak (Cyclic reference) when used as class property
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-192672@lists.php.net to get a copy of this message
From: tom at r dot je Operating system: * PHP version: 5.6.9 Package: Performance problem Bug Type: Bug Bug description:Closure causes memory leak (Cyclic reference) when used as class property Description: ------------ Because closures inside classes implicitly have a reference to $this, if a closure is used as a class property, this automatically creates a cyclic reference. Having read the page on GC here: http://php.net/manual/en/features.gc.collecting-cycles.php I can understand the problem, but the issue this causes is a memory leak any time a closure is used as a class property (Or in an array/data structure in a class property) Consider the following code: <?php class X { private $largeStr; private $closure; public function foo() { $this->largestr = str_repeat('ABC', 10000000); $this->closure = function() {}; } } echo (memory_get_usage()/1024/1024) . 'mb<br >'; for ($i = 0; $i < 1000; $i++) { $x = new X; $x->foo(); unset($x); echo (memory_get_peak_usage()/1024/1024) . 'mb<br >'; } ?> Which outputs: 0.21446228027344mb 28.827682495117mb 57.438827514648mb 86.050003051758mb 114.66118621826mb Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 30000001 bytes) I have explicitly called unset() which I would hope would free the memory used by the class, clearly it doesn't. Similarly, adding public function __destruct() { unset($this->closure); } to the class does not help. I'm not sure there is an obvious fix for this but gc_collect_cycles() in the loop does solve it, I have to wonder why unset() doesn't just trigger gc_collect_cycles(). Presumably it can do it in a smarter way as well because it doesn't have to look through every defined variable. -- Edit bug report at https://bugs.php.net/bug.php?id=69639&edit=1 -- Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=69639&r=trysnapshot54 Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=69639&r=trysnapshot55 Try a snapshot (trunk): https://bugs.php.net/fix.php?id=69639&r=trysnapshottrunk Fixed in SVN: https://bugs.php.net/fix.php?id=69639&r=fixed Fixed in release: https://bugs.php.net/fix.php?id=69639&r=alreadyfixed Need backtrace: https://bugs.php.net/fix.php?id=69639&r=needtrace Need Reproduce Script: https://bugs.php.net/fix.php?id=69639&r=needscript Try newer version: https://bugs.php.net/fix.php?id=69639&r=oldversion Not developer issue: https://bugs.php.net/fix.php?id=69639&r=support Expected behavior: https://bugs.php.net/fix.php?id=69639&r=notwrong Not enough info: https://bugs.php.net/fix.php?id=69639&r=notenoughinfo Submitted twice: https://bugs.php.net/fix.php?id=69639&r=submittedtwice register_globals: https://bugs.php.net/fix.php?id=69639&r=globals PHP 4 support discontinued: https://bugs.php.net/fix.php?id=69639&r=php4 Daylight Savings: https://bugs.php.net/fix.php?id=69639&r=dst IIS Stability: https://bugs.php.net/fix.php?id=69639&r=isapi Install GNU Sed: https://bugs.php.net/fix.php?id=69639&r=gnused Floating point limitations: https://bugs.php.net/fix.php?id=69639&r=float No Zend Extensions: https://bugs.php.net/fix.php?id=69639&r=nozend MySQL Configuration Error: https://bugs.php.net/fix.php?id=69639&r=mysqlcfg

« previous php.bugs (#192672) next »