php-meminfo
php-meminfo copied to clipboard
Memory leak caused by meminfo_dump
Looks like meminfo_dump itself causes unreported memory leaks.
Background: I tried to trace back a memory leak to a suspected XMLDom issue by running a method call in a loop, but then noticed that the actual memory usage was caused by meminfo_dump in this specific case.
Isolated test code (part of a big Laravel command, but run in isolation):
public function dummy()
{
}
public function MemTest($iterations=1)
{
for ($iteration = 1; $iteration <= $iterations; $iteration++)
{
$this->dummy();
// $this->LoadXML(...);
$gc = gc_collect_cycles();
printf("MemTest %02d - gc: %d, peak mem: %5.3f MiB\n",
$iteration, $gc, memory_get_peak_usage(false)/1000000);
meminfo_dump(fopen(sprintf('meminfo-test-%02d.json', $iteration), 'w'));
}
}
This results in the following output:
Memtest - running 100 iterations...
MemTest 01 - gc: 0, peak mem: 13.677 MiB MemTest 02 - gc: 0, peak mem: 15.172 MiB MemTest 03 - gc: 0, peak mem: 15.501 MiB MemTest 04 - gc: 0, peak mem: 15.827 MiB MemTest 05 - gc: 0, peak mem: 16.153 MiB MemTest 06 - gc: 0, peak mem: 16.479 MiB MemTest 07 - gc: 0, peak mem: 16.805 MiB MemTest 08 - gc: 0, peak mem: 17.131 MiB ^C
So about 330 kB wasted on each iteration. See below for meminfo output for 1st and last iteration.
After commenting out the line meminfo_dump(...) the following - expected - output is returned:
Memtest - running 99 iterations...
MemTest 01 - gc: 0, peak mem: 13.676 MiB MemTest 02 - gc: 0, peak mem: 13.676 MiB MemTest 03 - gc: 0, peak mem: 13.676 MiB MemTest 04 - gc: 0, peak mem: 13.676 MiB MemTest 05 - gc: 0, peak mem: 13.676 MiB MemTest 06 - gc: 0, peak mem: 13.676 MiB MemTest 07 - gc: 0, peak mem: 13.676 MiB ... MemTest 96 - gc: 0, peak mem: 13.676 MiB MemTest 97 - gc: 0, peak mem: 13.676 MiB MemTest 98 - gc: 0, peak mem: 13.676 MiB MemTest 99 - gc: 0, peak mem: 13.676 MiB
Inspection of the meminfo dumps shows the same trend for overall memory usage but does not show any detail of where the memory went; this is consistent with the documentation which states that memory in extensions is not shown.
NOTE: this is based on a legacy version of PHP 7.0.30 which we need for an existing Laravel 5.5 based project; meminfo was built from source from the master branch today.
PHP 7.0.30 (cli) (built: May 9 2018 06:56:41) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans
meminfo summary, first iteration:
{
"header" : {
"memory_usage" : 13613016,
"memory_usage_real" : 14680064,
"peak_memory_usage" : 13677144,
"peak_memory_usage_real" : 14680064
},
| Type | Instances Count | Cumulated Self Size (bytes) |
|---|---|---|
| string | 6720 | 629831 |
| array | 1843 | 132696 |
| boolean | 1185 | 18960 |
| null | 1076 | 17216 |
| integer | 497 | 7952 |
| Closure | 231 | 16632 |
| Symfony\Component\Console\Input\InputOption | 112 | 8064 |
| Symfony\Component\Console\Input\InputDefinition | 83 | 5976 |
| Illuminate\Routing\Route | 68 | 4896 |
| Symfony\Component\Console\Input\InputArgument | 36 | 2592 |
| unknown | 15 | 240 |
| Symfony\Component\Console\Formatter\OutputFormatterStyle | 5 | 360 |
meminfo summary, final iteration:
{
"header" : {
"memory_usage" : 46240416,
"memory_usage_real" : 48234496,
"peak_memory_usage" : 47126928,
"peak_memory_usage_real" : 48234496
},
| Type | Instances Count | Cumulated Self Size (bytes) |
|---|---|---|
| string | 6703 | 629389 |
| array | 1821 | 131112 |
| boolean | 1185 | 18960 |
| null | 1076 | 17216 |
| integer | 497 | 7952 |
| Closure | 231 | 16632 |
| Symfony\Component\Console\Input\InputOption | 112 | 8064 |
| Symfony\Component\Console\Input\InputDefinition | 83 | 5976 |
| Illuminate\Routing\Route | 68 | 4896 |
| Symfony\Component\Console\Input\InputArgument | 36 | 2592 |
| unknown | 15 | 240 |
| Symfony\Component\Console\Formatter\OutputFormatterStyle | 5 | 360 |
Thanks @squio for this report,
We have some tests to make sure we don't leak: https://github.com/BitOne/php-meminfo/blob/master/extension/php7/tests/dump-memory_leak.phpt
But it seems it's not sufficient enough.
Do you have the same problem on a more recent version of PHP? Can you try without xdebug enabled? And finally, do you have any code that you can provide so I can do some testing?
Thank you very much!
Hi there, speaking of that test (tests/dump-memory_leak.phpt), compiling fails that particular test for me on some builds and passes on others, consistently.
- EL6 PHP 7.0: PASS
- EL6 PHP 7.1: FAIL
- EL6 PHP 7.2: FAIL
- EL6 PHP 7.3: PASS
- EL7 PHP 7.0: PASS
- EL7 PHP 7.1: PASS
- EL7 PHP 7.2: PASS
- EL7 PHP 7.3: FAIL
An example fail output from EL6 PHP 7.2:
=====================================================================
TEST RESULT SUMMARY
---------------------------------------------------------------------
Exts skipped : 0
Exts tested : 15
---------------------------------------------------------------------
Number of tests : 12 1
Tests skipped : 11 ( 91.7%) --------
Tests warned : 0 ( 0.0%) ( 0.0%)
Tests failed : 1 ( 8.3%) (100.0%)
Expected fail : 0 ( 0.0%) ( 0.0%)
Tests passed : 0 ( 0.0%) ( 0.0%)
---------------------------------------------------------------------
Time taken : 2 seconds
=====================================================================
=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
meminfo_dump check there's no memory leak [tests/dump-memory_leak.phpt]
=====================================================================
edit: added php 7.3 to results
@jc21 I am having the same problem on CentOS 6.9 running PHP 7.1.11. Tried it on a Docker container based on php:7.1-apache based on Debian 8 and it works, all tests passing. I will try to run some more tests to see if it is CentOS specific.
I was already having this issue from my PHP routines, which led me to try out this repo. The exact same amount of memory is leaking in the test (2097152 bytes), so I am thinking this might be something OS or PHP specific.
I've implemented the builds on a different hardware and now I'm getting different results:
- EL6 PHP 7.0: PASS
- EL6 PHP 7.1: FAIL
- EL6 PHP 7.2: FAIL
- EL6 PHP 7.3: FAIL (different)
- EL7 PHP 7.0: PASS
- EL7 PHP 7.1: PASS
- EL7 PHP 7.2: PASS
- EL7 PHP 7.3: PASS (different)
So my best guess is that this test is defunct in some way ¯_(ツ)_/¯
I managed to build a Docker image that is able to reproduce this issue.
docker pull gusantoniassi/php-meminfo-memory-leak-bug
docker run -it --rm gusantoniassi/php-meminfo-memory-leak-bug bash
cd /opt/php-meminfo/extension/php7
make test
# test dump-memory_leak.phpt should fail
As you can see from the Dockerfile the installation is pretty minimal, so I believe it is either an issue with EL6 or with the remirepo.net's PHP packages.