35

My dedicated server has 32GB RAM and the memory just goes up and up constantly and I have to reboot it daily now. This is costing me customers and money.

I am having a hard time finding where the memory leak is. All I can find online is people say "Use xdebug" but I haven't been able to find any xdebug tutorials on finding memory leaks. I have tried printing memory_get_usage before and after function calls but is that the right way to do it?

I have MANY php scripts running - some from visitors, others from cron jobs - and I need to find which one(s) of them is leaking memory and fix it ASAP but I don't even know how to determine if a given function is leaking memory or not.

I have tried printing memory_get_usage before a function call and after, and it goes up, but then if I call the function more than once, it doesn't go up anymore. Can someone please explain this and tell me how I can simply and easily tell if a PHP function has a memory leak?

Guy
  • 754
  • 1
  • 5
  • 16
  • I was considering doing that... copying the whole thing to another server and only run one piece at a time and see what causes it. Expensive and time-consuming though... There are no ways to unit test memory in PHP? – Guy Apr 17 '13 at 19:21
  • None I know of. I'm curious too. I voted you up, and maybe we'll both find out. – Tomáš Zato - Reinstate Monica Apr 17 '13 at 19:26
  • I agree with @TomášZato. You could make use of an `auto_append_file` script and the `memory_get_*` methods, to log all of your scripts and watch out for the heavy ones. – metadings Apr 17 '13 at 19:54
  • Have you tried monitoring the top memory consumers using `ps`? i.e. a simple cron job to dump output of `ps` (with appropriate flags) so you can see which processes are using the most memory each minute. Check your flavour of `ps` to sort by memory usage and output full process detail (e.g. process + full command line and environment.) – searlea Apr 17 '13 at 20:04

4 Answers4

28

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#.

MatthiasLaug
  • 2,786
  • 6
  • 25
  • 41
  • What about referenced vars? – Yousha Aleayoub Sep 04 '16 at 13:25
  • Your answer is 5 years old but still relevant. I have been using PHP for over 10 years now and when it comes to large-scale applications PHP (any version) shall not be in your list. – Aftab Naveed May 26 '18 at 15:17
  • 4
    I don't agree that PHP is not a great language. I have coded since 1981.I can code in Java, C#, etc. Most people are prejudiced against PHP. Facebook is PHP (re-branded?)! Java is promoted in academics. Even BASIC is great language. Each language has its good and bad.Java has a 30% to 60% more development ($$$) overhead than PHP! Try coding in Z-80. 80x86, MX6800x, etc... it is ALL ABOUT how good a programmer (engineer) you are! – Mr. de Silva Oct 15 '19 at 03:23
6

Look at this php-extension: https://github.com/arnaud-lb/php-memory-profiler. You will can dump information in different formats and simple analyze it by some tools such as: Google Performance Tools, KCacheGrind or QCacheGrind.

Volodymyr Chumak
  • 736
  • 6
  • 12
6

I found method which works pretty well for me:

  1. Install "php-memprof" extention. In you can Ubuntu run:

    sudo pecl install memprof

  2. Install "google-perftools". Again for Ubuntu:

    sudo apt-get install google-perftools

  3. Add this code to begining of your script:

    if (function_exists('memprof_enable')) {
        memprof_enable();
    }
    
  4. And this aroud place were you expexct to find memory leak:

    if (function_exists("memprof_dump_pprof"))
    {
        $time = microtime(true);
        $f = fopen("/tmp/profile_$time.heap", "w");
        memprof_dump_pprof($f);
        fclose($f);
        echo "Memory profile dumped. ";
    }
    

    In my case it was inside big cycle every 100 runs.

  5. Run google-pprof comparing 2 memory dumps:

    google-pprof --web --base=/tmp/profile_17.heap /tmp/profile_18.heap
    

    This will open svg image like this in your browser:

    sample from doc

    Description of numbers and names inside you can find in gperftools documentation

P.S. Fixing leaks on php-level will not guarantee you that there are no memory-leaks in interpreter. In my case I end up just with restarting sctipt in longer periods.

Community
  • 1
  • 1
red_led
  • 333
  • 3
  • 5
1

I'm not an expert on memory usage, but maybe this method will help you detect the problematic scripts:

Get information: 1. Use the apache access log files 2. Create your own memory usage log file (http://www.webhostingtalk.com/showthread.php?t=617742)

Check the time when the memory usage goes up and compare to the apache access log.

It will at least give you information whether the usage goes up slowly and constant or if it starts at a certain point.

Good luck!

Hashbrown
  • 11
  • 4