PHP Memory Profiling

PHP memory profiling

Xdebug reimplemented memory tracing in 2.6 (2018-01-29) which can be used in Qcachegrind or similar tool. Just make sure to select the memory option :)

From the docs:

Since Xdebug 2.6, the profiler also collects information about how much memory is being used, and which functions aGnd methods increased memory usage.

I'm not familiar with the format of the file, but it's Qcachegrind has worked great for me in tracing a couple memory issues.

qcachegrind sample

Application Profiling: Memory Usage

2MB is not that much -- it doesn't look surprising to me, at least ; I often see much higher values, when using a framework, even if not doing lots of SQL queries.

Note that the memory_limit, which defines how much memory a PHP script can use, if often set to at least 8MB -- and quite often 16 or even 32 MB.

if 1000 users accessed this page at the same time

First of all, are you sure your application will be successful enough to have one thousand users requesting a page at the same time ? Note that if you need need 1 second to generate a page (which is already a bit long), it means having 1,000 users requesting a page in that one second !

Then, anyway, your server will probably never support that load -- by default, I should add that Apache is generally configured to not serve more than something like 200 concurrent requests.

If you really expect to have 1,000 users at the same instant on your application, you'll have plenty of other problems, I'd say -- and you'll probably have to optimise a lot, and/or use more than one server.

Tools to visually analyze memory usage of a PHP app

As you probably know, Xdebug dropped the memory profiling support since the 2.* version. Please search for the "removed functions" string here: http://www.xdebug.org/updates.php

Removed functions

Removed support for Memory profiling as that didn't work properly.

So I've tried another tool and it worked well for me.

https://github.com/arnaud-lb/php-memory-profiler

This is what I've done on my Ubuntu server to enable it:

sudo apt-get install libjudy-dev libjudydebian1
sudo pecl install memprof
echo "extension=memprof.so" > /etc/php5/mods-available/memprof.ini
sudo php5enmod memprof
service apache2 restart

And then in my code:

<?php

memprof_enable();

// do your stuff

memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));

Finally open the callgrind.out file with KCachegrind

Using Google gperftools (recommended!)

First of all install the Google gperftools by downloading the latest package here: https://code.google.com/p/gperftools/

Then as always:

sudo apt-get update
sudo apt-get install libunwind-dev -y
./configure
make
make install

Now in your code:

memprof_enable();

// do your magic

memprof_dump_pprof(fopen("/tmp/profile.heap", "w"));

Then open your terminal and launch:

pprof --web /tmp/profile.heap

pprof will create a new window in your existing browser session with something like shown below:

PHP memory profiling with memprof and gperftools

Xhprof + Xhgui (the best in my opinion to profile both cpu and memory)

With Xhprof and Xhgui you can profile the cpu usage as well or just the memory usage if that's your issue at the moment.
It's a very complete solutions, it gives you full control and the logs can be written both on mongo or in the filesystem.

For more details see my answer here.

Blackfire

Blackfire is a PHP profiler by SensioLabs, the Symfony2 guys https://blackfire.io/

If you use puphpet to set up your virtual machine you'll be happy to know it's supported ;-)

How to find which PHP script is leaking memory?

You could do various things, but first you should try to avoid the creation of memory leaks in the first place.

Let me clarify: PHP is a scripting language and it is not designed for long running scripts, so it's memory management is not the best on the market. But why should it be? It's purpose is to be called on a request level so its running scope is quite small (not more than 2 - 3 seconds). Everything else should be put in the background.

What can I do against memory leaks?

  1. If you are at a version below 5.4 you need to take care of circle references, since those are not garbage collected.

  2. If you need a script to be run continuously, you might think about a different approach. Do try a while(true) implementation, but wrap supervisor (http://supervisord.org) around your script, and let it be called after it ends. That way you make 100% sure you never get memory leaks.

  3. You could use xdebug to profile your scripts one by one and find out, where a lot of memory is consumed.

  4. You could implement a destructor to unset all you references if the class is not of any need anymore.

    public function __destruct(){
    $this->cleanup();
    }

    public function cleanup() {
    //cleanup everything from attributes
    foreach (get_class_vars(__CLASS__) as $clsVar => $_) {
    unset($this->$clsVar);
    }

    //cleanup all objects inside data array
    if (is_array($this->_data)) {
    foreach ($this->_data as $value) {
    if (is_object($value) && method_exists($value, 'cleanUp')) {
    $value->cleanUp();
    }
    }
    }
    }
  5. Read through the PHP documentation regarding garbage collection http://us3.php.net/manual/en/features.gc.php

  6. Avoid global variables, because those are never garbage collected and need to be unset explicitly. If you are using a Framework like ZF or Symfony that might not be possible, since you would break functionality if you do.

Last but not least I want to emphasize once again, PHP is not suited for long running scripts! If you have things to do, that need to run continuously you should not crumble your head with memory leaks in PHP, but take the time to learn a more sophisticated language like JAVA or C#.



Related Topics



Leave a reply



Submit