Skip to content

Unknown memory leak in PHP 8.2 FPM #13775

Closed

Description

@jreklund

Description

This is an follow up on the issue hi-jacking I did earlier (sorry!). I haven't been able to replicate the issue in development or on our test servers during this time. So I tried a memory profiler on the production server, without any luck. Now I need some new advice from some experts!
#8646 (comment)

After running our application for about an hour we start to see an unhealthy amount of RAM usage. Fast forward a couple of hours and our sever will run out of RAM and start writing to disk instead.

PHP versions tested: 8.2.17, 8.2.14, 8.2.12, 8.2.9, 8.2.8, 8.2.7, 8.2.5, 8.2.4
Configuration: #8646 (comment)

sudo add-apt-repository ppa:ondrej/php
sudo apt update -y
sudo apt install php8.1-common php8.1-fpm php8.1-gd php8.1-mysql php8.1-mbstring php8.1-intl php8.1-xml php8.1-redis php8.1-curl

12 days with PHP 8.1.27 and we utilize 1.3 GB of RAM. Same utilization can be seen using PHP 5.6 - 8.1.

php-memory-2024-03-20-81


Around 3 hours with PHP 8.2.17 and we utilize 4.5 GB of RAM. This will build up to use all available memory.

php-memory-2024-03-20-82


I tried to use valgrind massif tool to locate the issue, but it's stable for 7 hours.

I have made two runs, using these settings, they give us the same behavior.
sudo valgrind --tool=massif /usr/sbin/php-fpm8.2
sudo valgrind --tool=massif /usr/sbin/php-fpm8.2 --nodaemonize --fpm-config /etc/php/8.2/fpm/php-fpm.conf

php-memory-2024-03-20-massif

    MB
4.480^                                #                                       
     |                                #    :::::::::::@:::::::::::::::::@:@:  
     |                                #::::: :: : ::: @:::: ::: :::: :::@:@:: 
     |                                #:  :: :: : ::: @:::: ::: :::: :::@:@:: 
     |                                #:  :: :: : ::: @:::: ::: :::: :::@:@:: 
     |                               @#:  :: :: : ::: @:::: ::: :::: :::@:@:: 
     |                               @#:  :: :: : ::: @:::: ::: :::: :::@:@:: 
     |                               @#:  :: :: : ::: @:::: ::: :::: :::@:@:: 
     |                               @#:  :: :: : ::: @:::: ::: :::: :::@:@:: 
     |                              @@#:  :: :: : ::: @:::: ::: :::: :::@:@:: 
     |                              @@#:  :: :: : ::: @:::: ::: :::: :::@:@:: 
     |                              @@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
     |                             @@@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
     |                         ::::@@@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
     |                      :::::: @@@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
     |             ::::::::::::::: @@@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
     |          :@::        :::::: @@@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
     |       ::::@::        :::::: @@@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
     |       : ::@::        :::::: @@@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
     |     ::: ::@::        :::::: @@@#:  :: :: : ::: @:::: ::: :::: :::@:@:::
   0 +----------------------------------------------------------------------->Mi
     0                                                                   121.6

Number of snapshots: 52
 Detailed snapshots: [6, 16, 17, 18, 19 (peak), 30, 45, 47]

@nielsdos You helped me out before and stated there was another way of using a memory profiler. I didn't see any memory leak using Valgrid thought. But these servers fail 100% of time not using Valgrid.

Did you observe memory leaking behaviour of this run? If yes, that means the problem is somehow not originating from a persistent allocation, and we can give instructions on how to include request memory inside the graphs.

  • Is it still worth tracking request?

If not, I will start testing our application with PHP 8.2.0 to see if it's compatible before going the git-bisect route.

PHP Version

8.2.17

Operating System

Ubuntu 22.04.4

Activity

  1. ndossche commented on Mar 21, 2024

    @ndossche
    Member

    Do you use any third party extensions as well? If yes, I wonder if there may be a leak there too.

    Given the information you gave and the tests you did with Valgrind and massif, it seems indeed persistent allocations are not the problem.

    I'd say it is worth trying to track request allocations too. To do so, you need to set the environment variable USE_ZEND_ALLOC to 0. This disables Zend's allocator and uses system malloc instead. This will make request allocations visible to Valgrind and massif.
    Beware that this may reduce the performance of your code by a few percentage points though.

    Edit: although Zend's memory manager should clean up unfreed memory after request shutdown...

  2. jreklund commented on Mar 22, 2024

    @jreklund
    Author

    We are using php-redis, other than that I would say it's vanilla/core extensions.

    Core
    ctype
    curl
    date
    dom
    exif
    fileinfo
    filter
    ftp
    gd
    hash
    iconv
    igbinary
    intl
    json
    libxml
    mbstring
    mysqli
    mysqlnd
    openssl
    pcntl
    pcre
    PDO
    pdo_mysql
    random
    readline
    redis
    Reflection
    session
    shmop
    SimpleXML
    sockets
    sodium
    SPL
    standard
    sysvmsg
    sysvsem
    sysvshm
    tokenizer
    xml
    xmlreader
    xmlwriter
    xsl
    Zend OPcache
    zlib
    

    I have now made a 6,5 hour Valgrind test with USE_ZEND_ALLOC disabled, and according to "htop" I can see a larger memory consumption, but nothing obvious to my eyes in the massif logs. It was a slow build-up and nothing like we use it normally, but over time I guess it would fill up.

    php-memory-2024-03-22-massif

        MB
    4.481^                                  #                                     
         |                                  #    :::::::::::@@@::@:::::::@::::::: 
         |                                  #::::: :::::::::@ @: @: :::::@: ::::: 
         |                                  #: ::: :::::::::@ @: @: :::::@: ::::: 
         |                                  #: ::: :::::::::@ @: @: :::::@: ::::: 
         |                                  #: ::: :::::::::@ @: @: :::::@: ::::: 
         |                                @@#: ::: :::::::::@ @: @: :::::@: ::::: 
         |                                @ #: ::: :::::::::@ @: @: :::::@: ::::: 
         |                                @ #: ::: :::::::::@ @: @: :::::@: ::::: 
         |                               @@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |                               @@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |                               @@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |                              :@@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |                          ::@::@@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |                       :::: @ :@@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |                       :::: @ :@@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |          ::::@@@@@@@@@:::: @ :@@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |       :::::: @        :::: @ :@@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |       : :::: @        :::: @ :@@ #: ::: :::::::::@ @: @: :::::@: ::::::
         |     ::: :::: @        :::: @ :@@ #: ::: :::::::::@ @: @: :::::@: ::::::
       0 +----------------------------------------------------------------------->Mi
         0                                                                   116.5
    

    massif.out.zip <-- download logs here


    I read in Generating a valgrind log that you can enable ZEND_DONT_UNLOAD_MODULES, is that for e.g. tracking third party extensions like redis?

  3. ndossche commented on Mar 22, 2024

    @ndossche
    Member

    I don't really notice anything weird, but that data . I'm sorry, but I don't really have an idea what might be going on.
    It's going to be very hard also without a reproducer. Bisecting is an option but might be painful to go through. The advantage is that we might get an exact commit though where it broke.

    I read in Generating a valgrind log that you can enable ZEND_DONT_UNLOAD_MODULES, is that for e.g. tracking third party extensions like redis?

    The allocations will be tracked in any case, but the advantage of using this environment variable is that modules will not be unloaded and therefore symbol names will be visible in stack traces of third party modules.

  4. jreklund commented on Mar 22, 2024

    @jreklund
    Author

    Thanks for taking a look! I haven't been able to find a reproducer, so next step will be set up a test environment to learn how to make our production environment co-exist with a manually built PHP.

    It looks like it's only 10 steps to find the correct commit, but we will need to run the good one for a while, so will take some time for me to set it up.

    AFAIK, this is the correct way to start testing it:

    git clone https://github.com/php/php-src.git
    git checkout php-8.2.4
    git bisect start
    git bisect bad
    git bisect good php-8.1.27
    # Bisecting: a merge base must be tested
    # [0f21cbc57c0f210cc5ea35b78f354cf2e0949e0e] Fix GH-10715: phpdbg heap buffer overflow -- by misuse of the option "--run"
    # build PHP
    git bisect good/bad
    # (repeat from build PHP)
    
  5. ndossche commented on Mar 22, 2024

    @ndossche
    Member

    AFAIK, this is the correct way to start testing it:

    That looks right. It's possible you may need to re-run buildconf and configure too when building PHP, during bisection, because internal APIs and build files changed between PHP 8.1 and PHP 8.2.

  6. 25 remaining items

  7. jreklund commented on Jul 4, 2024

    @jreklund
    Author

    Hi! Your latest patch seem stable. Have been running it for 8 hours now. Will leave it over night.

    /proc/$pid/maps from a sub-process reaching 80 MB:
    php.3107394.maps.txt

    Screenshot 2024-07-04 175413

  8. arnaud-lb commented on Jul 4, 2024

    @arnaud-lb
    Member

    Great! I will see if we can merge this, then.

  9. jreklund commented on Jul 5, 2024

    @jreklund
    Author

    No leaks after around 24 hours, so no long time surprises either. 🎉

    Will keep it running for around 8 hours more before I switch back. Will be going on vacation and don't want any surprises.

    Thank you everyone for your help with my issue and development of PHP in general!

    php-2024-07-05

  10. kanevbg commented on Jul 5, 2024

    @kanevbg

    Great job. I know that PHP 8.1 is out of active support, but is there any chance that being merged for 8.1 too as being fundamental memory issue? Will be great to get it merged at least in 8.1 too :)

  11. jreklund commented on Jul 5, 2024

    @jreklund
    Author

    @kanevbg This specific problem don't exists in PHP 8.1 or earlier. The code that caused the problem (for us) was introduced in PHP 8.2.

  12. DPlachkov1991 commented on Jul 5, 2024

    @DPlachkov1991

    Great! I will see if we can merge this, then.

    Was this released with PHP Version 8.2.21 04 Jul 2024(yesterday) or will it be on a later stage?

  13. ndossche commented on Jul 5, 2024

    @ndossche
    Member

    Was this released with PHP Version 8.2.21 04 Jul 2024(yesterday) or will it be on a later stage?

    No, it will be part of a future release of 8.2.x.

  14. added a commit that references this issue on Jul 22, 2024
    929536b
  15. arnaud-lb commented on Jul 22, 2024

    @arnaud-lb
    Member

    #14793 has been merged.

    This prevents the opcache SHM from being allocated too close to the heap in most cases, which is deemed to trigger the memory leak.

    Non-PIE builds may still allocate the opcache SHM just after the heap when JIT is enabled, but it may be possible to fix that as well if we get more insights regarding the root cause.

  16. jreklund commented on Jul 22, 2024

    @jreklund
    Author

    Thanks! Will try out the official patch in 3 weeks, when I get back to work. Hopefully I or someone else will find the real cause of the problem in the future.

  17. cpernot-hf commented on Aug 2, 2024

    @cpernot-hf

    @arnaud-lb #14793 does not seem to have been merged, but only closed.

    The code does not appear in the PHP-8.2.2 tag : https://github.com/php/php-src/blob/PHP-8.2.22/ext/opcache/shared_alloc_mmap.c#L48

    Do you have more information ?

  18. ndossche commented on Aug 2, 2024

    @ndossche
    Member

    @cpernot-hf The 8.2.22 version was tagged before the fix was merged in to the 8.2.x branch. The fix will be included in 8.2.23 which will be released in september. See

    php-src/NEWS

    Lines 32 to 33 in dc670cb

    . Fixed bug GH-13775 (Memory leak possibly related to opcache SHM placement).
    (Arnaud, nielsdos)

  19. jreklund commented on Aug 9, 2024

    @jreklund
    Author

    I'm back from vacation and have been evaluated the new fix available in PHP 8.2 branch and it works without issues. Have been running it for over 3 days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions