|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69639 Closure causes memory leak (Cyclic reference) when used as class property
Submitted: 2015-05-15 10:15 UTC Modified: 2016-12-17 14:43 UTC
From: tom at r dot je Assigned:
Status: Duplicate Package: Performance problem
PHP Version: 5.6.9 OS: *
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please !
Your email address:
Solve the problem:
24 - 5 = ?
Subscribe to this entry?

 [2015-05-15 10:15 UTC] tom at r dot je
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: 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:

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;
	echo (memory_get_peak_usage()/1024/1024) . 'mb<br >';


Which outputs:


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() {

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.


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2015-05-15 11:29 UTC]
-Status: Open +Status: Verified
 [2015-05-15 11:29 UTC]
As explained on the mentioned manual page, the garbage collection
is only triggered when the root buffer runs full. Its default size
is 10,000, so in your example the garbage collection is likely to
be never executed, because only 1,000 objects are created.

However, increasing the number of created objects by factor 100 to
100,000 and reducing the length of $largestr by the same factor,
results in the same behavior, what appears to be a bug.
 [2015-05-15 11:43 UTC]
Root issue is bug #60982: We do not run an automatic cycle collection on OOM or memory limit events.
 [2016-12-17 14:43 UTC]
-Status: Verified +Status: Duplicate
 [2016-12-17 14:43 UTC]
Closing as duplicate of the references bug, as this is a general GC issue not related to closures.
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Jul 25 06:01:30 2024 UTC