php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65743 Memory leak with opCache, XML and continue
Submitted: 2013-09-23 15:18 UTC Modified: 2014-12-19 20:59 UTC
Votes:12
Avg. Score:4.5 ± 0.8
Reproduced:11 of 11 (100.0%)
Same Version:3 (27.3%)
Same OS:3 (27.3%)
From: thomas dot koenig at web-eci dot com Assigned: nikic (profile)
Status: Closed Package: opcache
PHP Version: 5.4.20 OS: Debian Wheezy x64
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: thomas dot koenig at web-eci dot com
New email:
PHP Version: OS:

 

 [2013-09-23 15:18 UTC] thomas dot koenig at web-eci dot com
Description:
------------
Hello, everybody.

I noticed a problem while parsing XML with interlocked foreach loops : if I 
write 'continue 2' to continue the upper loop, this will consume virtual memory 
far faster than with a single 'continue' or 'break'.

In my exemple, I parse a small basic XML; when I use 'continue 2', I see that as 
much as 8MB are used for this tiny loop. (See actual result)

On the other hand, only around 256kB are used if I replace this 'continue 2' 
with 'break 2' (See expected result).

As you can see, this 'continue 2' leads the script to retain much more memory 
than needed, and that this virtual memory is retained even if the loops 
allocating this memory are finished. Furthermore, we used the 'continue 2' 
version on a server when parsing a 37MB XML file, and this leaded the script to 
fail because the OS prevented it to claim more than 2GB of virtual memory; as 
you can see, this isn't only a theoritical issue.

Awaiting a bugfix,

Regards.

Test script:
---------------
function testOpCache(){
  $tab1 = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  $tab2 = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j');
  $tab3 = array(1 => 'a', 2 => 'b', 3 => 'c', 4 => 'd', 5 => 'e', 6 => 'f', 7 => 'g', 8 => 'h', 9 => 'i', 10 => 'j');
  
  $xml = "
    <level1>
      <level2>info1</level2>
      <level2>info2</level2>
      <level2>info3</level2>
      <level2>info4</level2>
      <level2>info5</level2>
      <level2>
        <level3>subinfo1</level3>
        <level3>subinfo2</level3>
        <level3>subinfo3</level3>
        <level3>subinfo4</level3>
        <level3>
          <level4>subsubinfo1</level4>
          <level4>subsubinfo2</level4>
          <level4>subsubinfo3</level4>
          <level4>subsubinfo4</level4>
        </level3>
        <level3>
          <level4>subsubinfo1</level4>
          <level4>subsubinfo2</level4>
          <level4>subsubinfo3</level4>
          <level4>subsubinfo4</level4>
        </level3>
        <level3>
          <level4>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
          </level4>
          <level4>subsubinfo2</level4>
          <level4>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
          </level4>
          <level4>subsubinfo4</level4>
        </level3>
      </level2>
      <level2>
        <level3>subinfo1</level3>
        <level3>subinfo2</level3>
        <level3>subinfo3</level3>
        <level3>subinfo4</level3>
        <level3>
          <level4>subsubinfo1</level4>
          <level4>subsubinfo2</level4>
          <level4>subsubinfo3</level4>
          <level4>subsubinfo4</level4>
        </level3>
        <level3>
          <level4>subsubinfo1</level4>
          <level4>subsubinfo2</level4>
          <level4>subsubinfo3</level4>
          <level4>subsubinfo4</level4>
        </level3>
        <level3>
          <level4>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
          </level4>
          <level4>subsubinfo2</level4>
          <level4>subsubinfo3</level4>
          <level4>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
            <level5>aaa</level5>
          </level4>
        </level3>
      </level2>
    </level1>
  ";
  $dom = simplexml_load_string($xml);
  $tab4 = array();

  sm();
  foreach($tab1 as $t1){
    foreach($tab2 as $t2){
      foreach($tab3 as $t3){
        foreach($dom->xpath('/level1/level2') as $level2){
          foreach($level2->xpath('level3') as $level3){
            foreach($level3->xpath('level4') as $level4){
              foreach($level4->xpath('level5') as $level5){
                continue 2;
                //break 2;
              }
            }
          }
        }
      }
    }
  }
  sm();
}

function sm(){
  echo memory_get_usage()."\n";
}

testOpCache();


Expected result:
----------------
thomas@Koenig:~$ php /home/thomas/Desktop/tests/opcache-1.php 
239224
240120
thomas@Koenig:~$

Actual result:
--------------
thomas@Koenig:~$ php /home/thomas/Desktop/tests/opcache-1.php 
239200
8416616
thomas@Koenig:~$

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-12-17 11:08 UTC] php dot net at kingsquare dot nl
Just confirmed that this is still a real issue (tested with this exact same script on 5.6.3 / opdache 7.0.4-dev)

A work around for this issue that works is by having a label present and using 'goto' to mitigate the foreach. Something seems to be off with 'continue X' (where X is a level)
 [2014-12-18 02:04 UTC] thilo at eightysoft dot de
Some other information on this bug can be found here: https://stackoverflow.com/questions/23231675/php-5-5-memory-leak-when-using-continue-2-inside-two-foreach-loops
 [2014-12-18 08:05 UTC] david dot guyot at web-eci dot com
I am the sysadmin of Thomas Koenig, the bug reporter. Regarding the StackOverflow topic, I can confirm that, on our system, Opcache is active with full optimization, ie. 0xFFFF…
 [2014-12-19 20:59 UTC] nikic@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
 [2014-12-19 20:59 UTC] nikic@php.net
Fixed, see also https://bugs.php.net/bug.php?id=67111.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 13:01:28 2024 UTC