Is my Apache2 setup leaking memory?

Recently, I've noticed that my apache uses absurd amounts of memory on my Linode server (80MB more than it used to), and restarting apache2 seems to fix the issue.

I run SVN over apache, as well as mysql and tomcat on the server, but neither seems to be the issue. How do I go about debugging where apache is losing memory? Aside from SVN, it's really only hosting a wordpress blog, so I don't see where the leak could be occurring. I used a default install from the ubuntu 8.04 repositories.

Any help?


Solution 1:

A nuance of Apache's memory handling means it always appears to be eating more and more memory - top's VIRT value is often high when using prefork.c (which I assume you are):

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
10385 apache    15   0  376m  48m 3932 R 20.3  1.2   0:01.34 httpd
10423 apache    16   0  376m  46m 4576 S 15.0  1.2   0:01.09 httpd
10153 apache    15   0  337m  61m 4672 S 11.6  1.6   0:03.94 httpd
10419 apache    15   0  383m  54m 4696 S 11.6  1.4   0:01.00 httpd

The value you want to monitor is RES - this is the size of the greatest amount of memory that child thread has consumed (in my case, PHP is run as part of that thread, hence the "bloat" as libraries and data are loaded). The thread does not release the allocated memory, however when the apache process kills the thread after its maxrequests as per

<IfModule prefork.c>
MaxRequestsPerChild  1000

the thread will return to its native memory consumption. This is the same effect as restarting apache, although a restart involves a temporary loss of service (nothing is listening on port 80) whereas MaxRequestsPerChild only controls child threads, ensuring that there is still a service listening on port 80 (or wherever it's configured to listen).

To lower apache's total memory usage, ensure you are only loading the apache modules you require, and monitor apache's threads while you run a very large PHP script (ini_set('memory_limit', '128M');then recursively load data into an array - that should do it). Then, during real world usage, lower the MaxRequestsPerChild value until you see your apache RES at a reasonable level. Don't forget this is only lowering the possibility of a child thread running a large script at the beginning of its "life" (the more children that do this, the more total memory apache uses),

Here are some useful parameter tuning articles:

  • OnLamp LAMP stack tuning
  • Low apache memory usage
  • Apache max performance
  • High server memory usage tips