Memory leak under PHP 7

Discussion in 'PHP Toolkit' started by Scott Rycroft, Aug 29, 2017.

  1. Scott Rycroft

    Scott Rycroft New Member

    I am experiencing what appears to be a memory leak when running under PHP 7 / Zend Server 9.1. It appears that any toolkit call increases memory usage by the plug size. We ran into this after calling programs in a loop for a result set. It doesn't appear to matter what the toolkit call is - it could be a program/procedure call or a CL command.

    I've attached a minimum reproducible program where you can see memory usage increasing by the plug size until the memory limit is reached. Running the same code under PHP 5 / ZS 8.5 does not produce this issue.

    I've duplicated this on different systems as well.

    Has anyone else run into this or have any ideas?

    PHP 7 / ZS 9.1
    memLeakPHP7.png

    PHP 5.6 / ZS 8.5
    memLeakPHP5.png
     

    Attached Files:

  2. Alan

    Alan Administrator Staff Member

    Thanks for posting this, Scott. Looks like an interesting one.
     
  3. Alan

    Alan Administrator Staff Member

    Scott, I heard from Chelsea that the out-of-memory error occurs on the db2_execute() line, right?
     
  4. Scott Rycroft

    Scott Rycroft New Member

    Yes that's correct
     
  5. Alan

    Alan Administrator Staff Member

  6. Scott Rycroft

    Scott Rycroft New Member

    Thanks! I couldn't reproduce it without the toolkit, but it makes sense that it's likely an ibm_db2 issue.
     
  7. Alan

    Alan Administrator Staff Member

    Scott, it's most likely a PHP 7 garbage collection issue, actually. Not ibm_db2.
     
  8. Alan

    Alan Administrator Staff Member

    The bound variables should be garbage-collected when the function ends and the variables go out of local scope. That's PHP 7's job. It's possible that PHP 7 employs a sort of lazy garbage collection for the sake of performance, in which case it could be an issue of GC timing, or PHP 7 doesn't know the size of the output string in advance. Just conjecture, though.

    By the way, did you ever come up with a workaround? If not then I may have a suggestion.
     
  9. Scott Rycroft

    Scott Rycroft New Member

    Thanks Alan. Regarding GC I did try calling gc_collect_cycles() but it had no effect.
    I don't have a workaround at this time.
     
  10. Alan

    Alan Administrator Staff Member

    I've heard that Clark may be submitting an issue with PHP. Meanwhile, I will look for the workaround.
     
    Chelsea Fenton and Scott Rycroft like this.
  11. Clark Everetts

    Clark Everetts New Member

    I can confirm I have opened a ticket internally on this issue. The garbage collector runs when its root buffer of circular-referenced variables is full, or when you manually tell it to collect all existing circular references. I don't see circular references in the scripts exhibiting these memory leaks, and I don't see the root buffer getting full (with the scripts I've seen and written to reproduce the leaks). In most scripts, it is unlikely the garbage collector is run before the script ends.

    I see no difference in my test scripts when using unset() to explicitly destroy a variable instead of assigning it, say, an empty string (which is NOT the same as destroying it). I might stick my neck out a bit and say that this isn't a problem with the garbage collector, per se, although we are definitely seeing a memory leak in PHP 7, whereas there wasn't one in PHP 5. Note I'm not saying this a problem with ibm_db2, either. At this point, it's all questions with no answers. But they will come.
     
  12. Clark Everetts

    Clark Everetts New Member

    A debug build of PHP will be constructed to isolate exactly where the leak is occurring, but this script from Dmitry exhibits no memory leak (uses zend_string_extend to resize variable $x), demonstrating that the problem does not appear - at this point in the investigation - to be in PHP itself. The scripts thus far exhibiting the memory leak interact with the DB2 extension. Debug build will pinpoint where the problem is.
    <?php
    $a = str_repeat("a", 52);
    $b = str_repeat("b", 42);
    for ($i = 0; $i < 10000; $i++) {
    $x = $a;
    $x .= $b;
    echo "$i. " . memory_get_usage() . "\n";
    }
     
    Chelsea Fenton likes this.
  13. Clark Everetts

    Clark Everetts New Member

    After discussions between IBM and Rogue Wave R&D, a test fix is available on YiPs site:
    http://yips.idevcloud.com/wiki/index.php/XMLService/PHP
    Scroll down to the section "PHP ibm_db2 new features (test only)" and download the appropriate .so file. Save your current one! :)
     
  14. David Taylor

    David Taylor New Member

    I was just about to open a support ticket with Zend when my team member found this post. We were very happy to see this issue listed along with a possible fix. Unfortunately, the fix did not work for us, I saw no change. Our setup is as follows:
    Zend Server Version 9.1.0, Enterprise Edition
    PHP 7.1.3 (cli) (built: Mar 22 2017 15:23:35) ( NTS )
    Multiple LPARs, OS versions 7.2 and 7.3

    Our test script is simply creating a prepared statement with db2_prepare() and then within a loop of 10,000 iterations, performing a db2_execute() using a simple select query. I verified the ibm_db2 version in ZS shows 2.0.1-zs2, so I believe we updated the .so file properly.

    We have also tested this on an IBMi running ZS 8.5 with PHP 5.6 and all works properly.
    Clark, should we go ahead and open a support ticket with Zend at this point?

    Thanks,
    Dave Taylor (Frontier Communications)
     
  15. Clark Everetts

    Clark Everetts New Member

    I apologize for the delay in getting back to this thread, Dave.
    You can open a support case if you wish, but, just to confirm, you're seeing "Script execution halted (Allowed memory size of blah-blah exhausted (tried to allocate blah-blah bytes))"?

    And if you include something like:
    echo "$i. " . memory_get_usage() . "\n";
    in the loop, you definitely see increasing memory usage?
    - Clark
     
  16. David Taylor

    David Taylor New Member

    Clark,
    The delay is not a problem, thanks for the reply. I know better than to expect instant gratitude from a forum post.
    FYI, I have put in a support case with Zend, CAS-41972-T4C0G9. I hadn't heard back yet on that, I was going to give a call today.
    As for the error, ours is a little different. But yes, using memory_get_usage(), we can see the ever increasing memory. Running the same code on ZS 8.5 with PHP 5.6 works perfectly. The error we see from a command line script is "15329 Memory fault(coredump)". Here is some out put from our script, both from ZS 9 PHP 7 and from ZS 8.5 PHP 5.6:

    ZS 9 PHP 7
    Row Count: 1000 -- Memory 1591184 -- Time 27.657039165497
    Row Count: 2000 -- Memory 2303184 -- Time 23.991224050522
    Row Count: 3000 -- Memory 3015184 -- Time 39.821897983551
    ZS 8.5 PHP 5.6
    Row Count: 1000 -- Memory 142084 -- Time 26.096907138824
    Row Count: 2000 -- Memory 142080 -- Time 1.6618180274963
    Row Count: 3000 -- Memory 142080 -- Time 0.9051079750061

    Our test script was based off some actual code, although I did simplify it down to just a loop that used db2_execute() and got the same results. I have attached the script that was used to generate the above results.
    We noticed that there is an even newer version of ibm_db2 on the PECL site, https://pecl.php.net/package/ibm_db2/2.0.2.
     

    Attached Files:

  17. David Taylor

    David Taylor New Member

    We finally found out what the memory issue was. We utilize Zend Server on all of our systems. We recently had 4 new LPARs setup, each with a new install of Zend Server 9.1.2 with PHP 7.1.12. In ZS9, there is a new advanced Zray setting labeled "Enable in CLI Mode" that is on by default. This enables data collection by Zray while running command line PHP scripts. If you're familiar with Zray, you know it's a wonderful tool but very much a resource hog. I only think of Zray in an HTTP request environment, so never even considered it on the command line. Once we turned that option off, our command line scripts ran perfection with no memory bloat. Hope this helps somebody else down the road.
     

Share This Page