php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #47525 value returned from __call copied prematurely
Submitted: 2009-02-28 01:56 UTC Modified: 2009-05-04 20:15 UTC
From: rodricg at sellingsource dot com Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 5.2.9 OS: linux
Private report: No CVE-ID: None
 [2009-02-28 01:56 UTC] rodricg at sellingsource dot com
Description:
------------
Values returned from the magic __call method are copied immediately 
resulting in increased memory usage.

Reproduce code:
---------------
<?php

function mem($msg='') { echo ($msg ? $msg.": " : '').number_format(memory_get_usage(1))."\n"; }

class A
{
    public $str;
    public function __construct() { $this->str = str_repeat("a", 1000000); }
    public function __call($m, $a) {return $this->str;}
    public function getStr() {return $this->str;}
}

$a = new A(); mem('new A()');
$b = $a->str; mem('$a->str');
$c = $a->getStr(); mem('$a->getStr()');
$d = $a->magic(); mem('$a->magic()');

?>

Expected result:
----------------
new A(): 1,310,720
$a->str: 1,310,720
$a->getStr(): 1,310,720
$a->magic(): 1,310,720

Actual result:
--------------
new A(): 1,310,720
$a->str: 1,310,720
$a->getStr(): 1,310,720
$a->magic(): 2,359,296

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-05-02 03:01 UTC] jani@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

This is a side-effect of the Zend memory manager. If you run the script 
with PHP build with --enable-debug and like this:

# USE_ZEND_ALLOC=0 php test.php
new A(): 8,280
$a->str: 8,280
$a->getStr(): 8,280
$a->magic(): 8,280

You see that there is no leak or unnecessary "copying" anywhere.
 [2009-05-04 20:15 UTC] rodricg at sellingsource dot com
IMHO __call is breaking copy-on-write semantics.  At the very least it could be said that memory utilization with __call is less efficient than without it.  Despite setting of USE_ZEND_ALLOC.

USE_ZEND_ALLOC=1 valgrind php -n -d memory_limit=1024M b.php 100 getStr
malloc/free: 15,018 allocs, 13,296 frees, 4,253,597 bytes allocated.

USE_ZEND_ALLOC=1 valgrind php -n -d memory_limit=1024M b.php 100 magic
malloc/free: 15,118 allocs, 13,396 frees, 109,111,199 bytes allocated.

USE_ZEND_ALLOC=0 valgrind php -n -d memory_limit=1024M b.php 100 getStr
malloc/free: 18,181 allocs, 16,459 frees, 4,407,683 bytes allocated.

USE_ZEND_ALLOC=0 valgrind php -n -d memory_limit=1024M b.php 100 magic
malloc/free: 18,981 allocs, 17,259 frees, 104,439,576 bytes allocated.

http://bugs.pastebin.com/f754ba8cd
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu May 02 11:01:31 2024 UTC