php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76982 memory leak declaring closure in included file
Submitted: 2018-10-08 02:40 UTC Modified: 2021-03-01 10:44 UTC
Votes:84
Avg. Score:4.6 ± 0.6
Reproduced:72 of 76 (94.7%)
Same Version:15 (20.8%)
Same OS:50 (69.4%)
From: ryan dot brothers at gmail dot com Assigned:
Status: Verified Package: Scripting Engine problem
PHP Version: 7.2.10 OS: Linux
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: ryan dot brothers at gmail dot com
New email:
PHP Version: OS:

 

 [2018-10-08 02:40 UTC] ryan dot brothers at gmail dot com
Description:
------------
I am running PHP 7.2.10 on CentOS 7.  If I run the below script file1.php, the memory usage gradually increases until it hits the memory limit.  The memory usage should remain relatively constant.  It's related to declaring the closure in file2.php, as if I remove the closure, then the memory usage stays constant.

Also, the memory usage stays constant in PHP 5.6, so the issue is perhaps only in PHP 7 and later.


Test script:
---------------
file1.php
<?php
for ($i = 0; $i < 1000000; $i++)
{
	echo $i.' - '.number_format(memory_get_usage())."\n";

	require('file2.php');
}


file2.php:
<?php
$test_function = function()
{
};


Expected result:
----------------
Memory usage stays constant.

Actual result:
--------------
Memory usage increases until it hits the memory limit.


Patches

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-10-09 12:07 UTC] cmb@php.net
-Status: Open +Status: Verified
 [2018-10-09 12:07 UTC] cmb@php.net
This also happens on current master.  It works fine if file2.php
is inlined.  Neither a debug build nor valgrind
(ZEND_DONT_UNLOAD_MODULES=1 USE_ZEND_ALLOC=0) report a memory
leak, though.
 [2018-10-09 13:21 UTC] ryan dot brothers at gmail dot com
Thanks for confirming.  If it helps, the same problem also happens if you put "return;" as the first line of file2.php like the below, so it seems related to compiling perhaps, rather than executing.

file2.php:
<?php
return;

$test_function = function()
{
};
 [2019-05-27 21:28 UTC] tyler dot bannister at remote-learner dot net
I'm seeing the same problem even when I don't use a closure and instead just assign a variable.  I also saw the same problem, but to a lesser extent, with a print command.  I filed a report for that in Bug #78076, but it seems like there may be a common problem related to repeated requires/includes?
 [2019-06-27 20:23 UTC] goetas at gmail dot com
I manage to reproduce consistently the issue on all PHP 7.x versions

https://github.com/goetas/symfony-mem-leak contains the repo to reproduce the issue

https://travis-ci.org/goetas/symfony-mem-leak/builds/551488795 is one build that shows the issue on Travis

Discovered while trying to solve https://github.com/symfony/symfony/issues/32220
 [2019-06-28 15:10 UTC] goetas at gmail dot com
This bug is pretty serious when integrating the symfony dependency injection container in reactphp, phppm or swoole applications.

This https://travis-ci.org/goetas/symfony-mem-leak/builds/551710669 shows the leak in the default configuration of the symfony dependency injection
 [2021-02-19 17:16 UTC] nikic@php.net
The following pull request has been associated:

Patch Name: Reference dynamic functions through dynamic_defs
On GitHub:  https://github.com/php/php-src/pull/5595
Patch:      https://github.com/php/php-src/pull/5595.patch
 [2021-03-01 10:44 UTC] nikic@php.net
This leak is partially fixed in PHP 8.1. There's still a memory leak, but it's a constant leak of ~250 bytes per overwritten closure now.
 [2021-04-09 21:43 UTC] zoohie at gmail dot com
Problem occurs not only with closures but also with anonymous classes.
 [2021-10-06 09:23 UTC] michael dot vorisek at email dot cz
if (!class_exists(Test::class)) {
    class Test {
    }
}

is leaking too, even if the the if condition is satisfied only once, test https://github.com/php/php-src/pull/7562/files . Seems to be fixed in PHP 8.1, but only when opcache is enabled (which is not by default for CLI).
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Dec 06 07:01:29 2024 UTC