php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #79392 get_object_vars() memory leak
Submitted: 2020-03-18 12:01 UTC Modified: 2020-07-07 11:09 UTC
From: tomas914 at gmail dot com Assigned:
Status: Re-Opened Package: Performance problem
PHP Version: Irrelevant OS: Windows 10
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2020-03-18 12:01 UTC] tomas914 at gmail dot com
Description:
------------
I'm developing an app which uses storage with fairly large amount of objects that are created from unserialized cached data.

Objects properties are set by iterating through get_object_vars() which causes extremely high memory usage.

Provided is reduced test case for reproducing this issue. The difference between two create functions is only the amount of get_object_vars() calls which leads me to conclusion it's a memory leak.

Results are:
Create(): Memory usage: 28.72MB
CreateWithLeak(): Memory usage: 95.1MB

Test script:
---------------
abstract class ObjectVarsCache
{
    public static $vars = array();
}

class Test
{
    public $a;
    public $b;
    public $c;
    public $d;
    public $e;
    public $f;
    public $g;
    public $h;
    public $i;
    public $j;

    public function CreateWithLeak()
    {
        $vars = get_object_vars($this);
    }

    public function Create()
    {
        $vars = &ObjectVarsCache::$vars;
        if (!$vars)
            $vars = get_object_vars($this);
    }
}

$objects = array();

for ($i = 0; $i < 100000; ++$i)
{
    $object = new Test;
    //$object->Create(); // uncomment to compare
    $object->CreateWithLeak();

    $objects []= $object;
}

echo "Memory usage: ".round(memory_get_usage() / 1024 / 1024, 2)."MB, Peak memory usage: ".round(memory_get_peak_usage() / 1024 / 1024, 2)."MB";


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-03-18 12:05 UTC] tomas914 at gmail dot com
Issue is present in all PHP versions since at least 7.0, didn't test earlier ones.
 [2020-03-18 14:14 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2020-03-18 14:14 UTC] cmb@php.net
The supposed "leak" is the properties table of the objects, which
is built lazily, because it is often not needed.  However,
get_object_vars() requires the table to be built, and it is only
freed when the object is destroyed.
 [2020-07-07 10:31 UTC] robert at korulczyk dot pl
This really should be documented at https://www.php.net/manual/en/function.get-object-vars.php, since this is very surprising behavior. I have very similar use case where `get_object_vars($this)` was used in `toArray()` method. Finding source of memory usage increase took me 2-3 hours, because `get_object_vars()` was the last thing I suspected to leak. Especially that manually building this array does not affect memory usage.

No leak:

```
	public function toArray(): array {
		return [
			'a' => $this->a,
			'b' => $this->b,
			'c' => $this->c,
			'd' => $this->d,
			'e' => $this->e,
			'f' => $this->f,
			'g' => $this->g,
			'h' => $this->h,
			'i' => $this->i,
			'j' => $this->j,
		];
	}
```

Leak:

```
	public function toArray(): array {
		return get_object_vars($this);
	}
```
 [2020-07-07 11:09 UTC] cmb@php.net
-Status: Not a bug +Status: Re-Opened -Type: Bug +Type: Documentation Problem -Assigned To: cmb +Assigned To:
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Thu Oct 22 02:01:23 2020 UTC