php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #75914 Memory leak when anonymous function is assigned to the class variable
Submitted: 2018-02-04 14:04 UTC Modified: 2018-02-04 16:10 UTC
From: john357smith at gmail dot com Assigned:
Status: Not a bug Package: Performance problem
PHP Version: 7.2.2 OS: Linux
Private report: No CVE-ID: None
 [2018-02-04 14:04 UTC] john357smith at gmail dot com
Description:
------------
In case an anonymous function is assigned to the class variable (doesn't matter if public, private or protected) and a new class instance is created a memory is not freed at the end. To correctly free memory you have to set a class variable to null or call a garbage collector manually. See test script.


Test script:
---------------
class TestMem
{
  public $class_var = null;

  public function __construct()
  {
    $this->class_var = function() { };
  }
}

while (true)
{
  $frame = new TestMem();
  //$frame->class_var = null;

  //echo(gc_collect_cycles()."\n");
  echo(memory_get_usage()."\n");

  usleep(10000);
}


Expected result:
----------------
A memory usage is still on the same level.

Actual result:
--------------
A memory usage is constantly increasing.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-02-04 15:47 UTC] kelunik@php.net
-Status: Open +Status: Not a bug
 [2018-02-04 15:47 UTC] kelunik@php.net
There's no leak. You're creating a circular reference there. If you use gc_collect_cycles(), everything is fine.

If you remove the usleep(), you'll see that it runs totally fine even without gc_collect_cycles(). It just takes its time until the GC kicks in.
 [2018-02-04 16:06 UTC] john357smith at gmail dot com
Where in this example is defined circular reference? Anonymous function is empty and has no references anywhere. I'm aware that it is possible after "some" time a GC will free it but the problem is this is only the smallest example. The class could be (and in fact it is) much bigger in memory which leads for me to memory limit exceeded error.
 [2018-02-04 16:10 UTC] nikic@php.net
The closure contains an implicit reference to $this. You can avoid creating the cycle by using a static closure:

    $this->class_var = static function() { };

Of course, this will only work if your closure does not require access to $this.
 [2018-02-04 16:51 UTC] john357smith at gmail dot com
OK I see, thanks for an explanation.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 15:01:29 2024 UTC