php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80125 CallbackFilterIterator is leaking memory
Submitted: 2020-09-20 13:12 UTC Modified: 2020-09-23 20:08 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: mvorisek at mvorisek dot cz Assigned:
Status: Duplicate Package: Scripting Engine problem
PHP Version: 7.4.10 OS: linux
Private report: No CVE-ID: None
 [2020-09-20 13:12 UTC] mvorisek at mvorisek dot cz
Description:
------------
see test script, explicit GC does not help

the issues seems present when the given callback to CallbackFilterIterator is bound (eg. not static)

https://3v4l.org/UpmHK

Test script:
---------------
class IteratorWithFilter
{
    public $generator;

    public function __construct(array $data)
    {
        $this->generator = new \ArrayIterator($data);
    }

    public function filter()
    {
        $this->generator = new \CallbackFilterIterator($this->generator, function ($row)  {
            return true;
        });
        
        return $this;
    }
}

function createIterator() {
    $iter = new IteratorWithFilter([['a'], ['b']]);
    return $iter->filter();
}

for ($i = 0; $i < 50 * 1000; $i++) {
    createIterator();
    
    if (($i % 1000) === 0) {
        // gc_collect_cycles(); // explicit GC does not help...
        echo round(memory_get_usage() / (1024 * 1024), 3) . " MiB\n";
    }
}

Expected result:
----------------
reported memory usage should stay below 1 MiB

Actual result:
--------------
0.375 MiB
1.719 MiB
3.071 MiB
4.36 MiB
5.774 MiB
7.064 MiB
8.353 MiB
9.892 MiB
...

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-09-23 16:19 UTC] kalle@php.net
-Status: Open +Status: Not a bug
 [2020-09-23 16:19 UTC] kalle@php.net
You should declare the closure as `static` and you will get the desired result:
https://3v4l.org/QPlkq
 [2020-09-23 16:27 UTC] mvorisek at mvorisek dot cz
No! The CallbackFilterIterator must be GCable like any other object.

I simplified the test script (to use bound function with simple condition), I can not use static and I also mentioned this in the description. This is a clear bug to me.
 [2020-09-23 16:45 UTC] kalle@php.net
Then create a closure, and pass it, clone + bindTo on assignment it to the scope which you want:

https://3v4l.org/gemWn
 [2020-09-23 20:04 UTC] mvorisek at mvorisek dot cz
this is not working as well, Closure::bindTo is defined like "duplicate and bind", so you must assign the result

https://3v4l.org/Ggt54

then the issue remains - CallbackFilterIterator is not GCed even if there is no reference to it, it is a clear bug to me and it should be fixed
 [2020-09-23 20:08 UTC] nikic@php.net
-Status: Not a bug +Status: Duplicate
 [2020-09-23 20:08 UTC] nikic@php.net
Duplicate of bug #65387.
 [2020-09-29 10:00 UTC] mvorisek at mvorisek dot cz
Here is a solution using WeakReference:

https://3v4l.org/U3h2Q

I wonder if this can be fixed in php directly - using proper GCable solution or even with WeakReference
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 13:01:29 2024 UTC