[PATCH] Memory leak when downloading attachments
|Reported by:||jeblair||Owned by:|
We observed unusally high Apache memory usage when downloading large attachments in 0.2-alpha. The effect is cumulative, suggesting a memory leak. This is a serious problem -- multiple users downloading attachments were able to cause our webmail servers to run out of memory.
Steps to replicate problem
If you want to replicate the problem, here are the steps I used:
1) Prepare your mailbox with several emails with large (suggest 2MB to 10MB or more) binary (so they will be base64 encoded) attachments. In order to see a cumulative effect, you will need to download attachments from different emails.
2) Use the prefork MPM with these settings:
<IfModule prefork.c> StartServers 1 MinSpareServers 1 MaxSpareServers 1 ServerLimit 1 MaxClients 1 MaxRequestsPerChild 4000 </IfModule>
This will cause there to be only one Apache process handling your requests, so that you can see the effect on memory by watching a single process.
3) Browse to each message in turn and download the attachment. You should see the memory usage of the httpd process increase each time. It may baloon a bit, but it will always return to a level higher than the previous message. For instance, in my testing, I saw the following:
19MB resident after opening a folder to load RC's php files 24MB resident after d/l a 2MB attachment 29MB resident after d/l a 3MB attachment 53MB resident after d/l a 15MB attachment
With, of course, corresponding increases in the virtual size of the process as well (from 345MB to 379MB).
After applying the fix below, and repeating the experiment, the memory usage does not increase from the base level of 19MB resident after downloading several attachments.
I've identified two contributing factors. The first is that the index.php sets output buffering before initializing RCMAIL, so the check to turn of output buffering when downloading attachments doesn't work. Simply moving the initializer for RCMAIL to before the buffering code causes that to work as intended.
Secondly, in imap.inc, the flush() call after base64_decode causes PHP to use more memory than otherwise. It is not needed, and removing it returns memory usage to normal patterns.
I'm attaching a patch that makes these changes.