Bug #81142 [Asn]: PHP 7.3+ memory leak when unserialize() is used on an associative array
| From: | cmb@php.net | Date: | Wed, 16 Jun 2021 14:32:35 +0000 |
| Subject: | Bug #81142 [Asn]: PHP 7.3+ memory leak when unserialize() is used on an associative array | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-234438@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=81142&edit=1
ID: 81142
Updated by: cmb@php.net
Reported by: jnelson at archive dot org
Summary: PHP 7.3+ memory leak when unserialize() is used on
an associative array
Status: Assigned
Type: Bug
Package: Arrays related
PHP Version: 7.3.28
Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
Note that PHP-7.3 is no longer actively supported, so a patch can
target PHP-7.4 at most.
Previous Comments:
------------------------------------------------------------------------
[2021-06-16 14:31:37] cmb@php.net
The following pull request has been associated:
Patch Name: Fix #81142: memory leak when unserialize()ing associative array
On GitHub: https://github.com/php/php-src/pull/7160
Patch: https://github.com/php/php-src/pull/7160.patch
------------------------------------------------------------------------
[2021-06-16 12:11:21] cmb@php.net
First, I suggest to use something like
<?php
$mem0 = memory_get_usage();
for ($ctr = 0; $ctr < 50000; $ctr++)
load("foo_$ctr");
$mem1 = memory_get_usage();
var_dump($mem1 - $mem0);
?>
to see the *relative* memory usage.
Anyhow, as of PHP 7.3.0, unserialized string keys are interned[1].
If OPcache is enabled, there is actually only one copy for all
50.000 keys. If OPcache is disabled, these strings are allocated
permanently in process memory.
[1] <https://github.com/php/php-src/commit/03da5f8e30cc65584d38d478ea566062ff99579b>
------------------------------------------------------------------------
[2021-06-15 17:27:47] jnelson at archive dot org
Description:
------------
As seen here: https://3v4l.org/KPJ62#focus=eol
This program loops thousands of times calling serialize() and unserialize() on associative arrays
with a string key and an integer value without holding long-term references to any of the data.
Prior to 7.3, this program would peak at a few hundred KB. With 7.3.0 forward, this program
consumes megabytes.
The two flags at the top of the program can be used to confirm (a) the memory leak only occurs with
associative arrays, and (b) it's caused by unserialize() and not serialize().
Test script:
---------------
The core of the linked program to repro the problem:
function load($str) {
$php = serialize([ $str => 1 ]);
unserialize($php);
}
for ($ctr = 0; $ctr < 50000; $ctr++)
load("foo_$ctr");
echo memory_get_peak_usage();
Expected result:
----------------
Prior to 7.3.0, my linked program produces this output (or similar numbers):
Usage: 377.99 K
Peak: 414.33 K
Actual result:
--------------
With 7.3.0 to 8.0.3, the numbers look like this:
Usage: 4.73 M
Peak: 5.34 M
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=81142&edit=1