php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #47103 memory leak using foreach and references
Submitted: 2009-01-14 16:35 UTC Modified: 2009-04-08 15:50 UTC
Votes:8
Avg. Score:3.9 ± 1.4
Reproduced:7 of 7 (100.0%)
Same Version:5 (71.4%)
Same OS:3 (42.9%)
From: soywiz at gmail dot com Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 5.*CVS,6CVS (2009-01-15) OS: *
Private report: No CVE-ID: None
 [2009-01-14 16:35 UTC] soywiz at gmail dot com
Description:
------------
This snippet causes an out of memory. It seems that it's duplicating the value (it's trying to allocate a memory chunk as large as each element on the array) and it's not freeing it.

The problem persists even with a unset($v); within the foreach.

I reproduced it using php 5.2.8-cli on windows and php 5.2.5-cgi on linux.

I think it should work, but maybe it's a php feature?

Reproduce code:
---------------
<?php
	$a = array_fill(0, 99999, str_repeat('*', 9991));
	foreach ($a as &$v) ;
?>


Expected result:
----------------
Don't waste all the memory

Actual result:
--------------
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 9992 bytes) in test.php on line 3

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-01-14 17:35 UTC] crrodriguez at opensuse dot org
looks like expected, do not use foreach value by reference, it is know to have "apparently unexpected behaviors" that are normal.
 [2009-01-15 14:51 UTC] jani@php.net
This is NOT expected but might not be fixable. And foreach with reference is supposed to work without leaks.
 [2009-01-15 14:52 UTC] jani@php.net
This worked: 
# php -dmemory_limit=1000M t.php 
int(1018887988)

That number is from memory_get_usage() after the foreach.. :)
 [2009-04-08 15:50 UTC] lbarnaud@php.net
This is not a bug.

> $a = array_fill(0, 99999, str_repeat('*', 9991));

This adds 99999 times the *same* string to the array. This string ends with a refcount of 99999, and the array occupies only the memory required for *one* string of 9991 bytes.

> foreach ($a as &$v) ;

At this point the engine must duplicate the string, place it at the current index, and return a reference to it (because if you assign to it, you do not want all values of the array to be changed at once).

When you unset $v, you remove a reference from it, and leave a copy in the array.

You get closely the same memory usage with the following script, which does the same thing:

$a = array();
for($i = 0; $i < 99999; ++$i) {
        $a[] =  str_repeat('*', 9991);
}
foreach ($a as &$v);

 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Wed Jul 16 20:01:32 2025 UTC