|  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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Bug Type:
From: tom at r dot je
New email:
PHP Version: OS:


 [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-2023 The PHP Group
All rights reserved.
Last updated: Thu Oct 05 02:01:24 2023 UTC