php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65340 Memory leak when using magic __set ?
Submitted: 2013-07-25 21:38 UTC Modified: 2017-02-16 12:38 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (100.0%)
From: vitalif at mail dot ru Assigned: nikic (profile)
Status: Closed Package: Class/Object related
PHP Version: 5.5.1 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: vitalif at mail dot ru
New email:
PHP Version: OS:

 

 [2013-07-25 21:38 UTC] vitalif at mail dot ru
Description:
------------
Hello!

I've discovered that when setting properties via __set() the object takes much more memory than it should. It's reproducible at least on PHP 5.5 and 5.4. Is it a memory leak?

Test script:
---------------
<?php

// Memory leak somewhere around __set?

class A
{
    var $data = array();
    function __get($k)
    {
        return $this->data[$k];
    }
    function __set($k, $v)
    {
        return $this->data[$k] = $v;
    }
}

$b = new A();

for ($i = 0; $i < 500000; $i++)
    $b->{"a$i"} = 'abc';
var_dump(memory_get_usage()); // int(78318488) - why so big?
$c = clone $b;
unset($b);
var_dump(memory_get_usage()); // int(42220972) - OK

unset($c);
$b = new A();
for ($i = 0; $i < 500000; $i++)
    $b->__set("a$i", 'abc');
var_dump(memory_get_usage()); // int(42221492) - OK


Expected result:
----------------
I expect roughly the same memory usage at all three points. Like:

int(42220972)
int(42220972)
int(42221492)

Actual result:
--------------
The first value is much bigger:

int(78318488)
int(42220972)
int(42221492)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-07-26 01:51 UTC] felipe@php.net
See bug #48197
 [2013-07-27 21:32 UTC] vitalif at mail dot ru
I don't think bug #48197 is related to this issue... There are no memory leaks. I.e. extra alloc done by __call in that bug is freed without problem (if you remove "$b[$i] =" and just throw away the value after each call).

And here I describe that an identical object takes twice more memory if you write in its array property using __set.
 [2013-10-05 22:04 UTC] vitalif at mail dot ru
Anyone? I've rechecked it on 5.5.4 - the bug is still there.
 [2015-03-19 12:12 UTC] php at bof dot de
Just tested with 5.6.7, issue is reproducible.
 [2015-08-28 21:21 UTC] nikic@php.net
The reason for this are property recursion guards. In PHP 5 32bit these take 72 bytes per distinct property name that was used with __get/etc. so in this case it would be 72*500000 bytes, which matches your numbers.
 [2015-08-28 21:30 UTC] vitalif at mail dot ru
But of course it's still a bug? :)
 [2017-02-16 11:35 UTC] nikic@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
 [2017-02-16 11:35 UTC] nikic@php.net
This issue has been fixed in PHP 7.1. Memory usage should now be constant for typical uses (no recursion over different property names) of magic getters/setters.
 [2017-02-16 12:25 UTC] ealexs at gmail dot com
Can you please explain: "no recursion over different property names". 
You mean the magic setter should not trigger another magic setter ? Would this apply on the object itself ($this) or it can also affect other objects ?

Thanks, Alex
 [2017-02-16 12:38 UTC] nikic@php.net
@ealexs: A magic accessor should not trigger a magic accessor on a different property name on the same object. $a->__get('x') -> $a->__set('x') is fine. $a->__get('x') -> $b->__get('y') is fine. $a->__get('x') -> $a->__get('y') may still lead to unbounded memory growth, if this is done for many distinct property names.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Wed Jan 08 07:01:29 2025 UTC