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
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: rodricg at sellingsource dot com
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2025 The PHP Group
All rights reserved.
Last updated: Wed Jan 08 06:01:28 2025 UTC