[imp] Cannot download large folder

Andrew Morgan morgan at orst.edu
Tue Jul 17 21:15:34 UTC 2007


On Tue, 17 Jul 2007, Chuck Hagenbuch wrote:

> Quoting Andrew Morgan <morgan at orst.edu>:
>
>>>> A more useful question might be, "Why does it require so much memory
>>>> to download a folder and how can the memory footprint be reduced?"
>>>> Note - I can trigger this error on my system also with a mailbox
>>>> that is approximately 1/3 my php memory limit.
>>> 
>>> If someone wants to trace this a bit, that'd be great.
>> 
>> Can you give me some directions on how to get started tracing memory usage? 
>> I've never traced a PHP application.  :)
>
> http://us.php.net/memory-get-usage
>
> If that's not enough, xdebug is the next step (http://xdebug.org/).

That was easy!

I added some simple debug statements to print out the memory usage at 
various steps in imp/lib/Folder.php.  I printed out the memory usage after 
each message was retrieved inside the 'for' loop, at the end of the loop, 
and after the str_replace.  Here were my results:

-----------------------------------------------------------------
Jul 17 13:25:40 webmail4 HORDE[1819]: [imp] Memory allocated: 7661556 [on 
line 603 of "/var/www-test/horde/imp/lib/Folder.php"]

... Many messages go by with memory usage increasing gradually according 
to the size of the message ...

Jul 17 13:26:23 webmail4 HORDE[1819]: [imp] Memory allocated: 51898876 [on 
line 603 of "/var/www-test/horde/imp/lib/Folder.php"]
Jul 17 13:26:23 webmail4 HORDE[1819]: [imp] Memory allocated after loop: 
51899260 [on line 610 of "/var/www-test/horde/imp/lib/Folder.php"]
-----------------------------------------------------------------

At this point it apparently was stopped for exceeding the php memory limit 
(100MB on my system).


Here are the results for a smaller folder that does not exceed the memory 
limit:

-----------------------------------------------------------------
Jul 17 13:33:15 webmail4 HORDE[2427]: [imp] Memory allocated: 7634344 [on 
line 603 of "/var/www-test/horde/imp/lib/Folder.php"]

... etc etc ...

Jul 17 13:33:17 webmail4 HORDE[2427]: [imp] Memory allocated: 18452336 [on 
line 603 of "/var/www-test/horde/imp/lib/Folder.php"]
Jul 17 13:33:17 webmail4 HORDE[2427]: [imp] Memory allocated after loop: 
18452756 [on line 610 of "/var/www-test/horde/imp/lib/Folder.php"]
Jul 17 13:33:17 webmail4 HORDE[2427]: [imp] Memory allocated after 
str_replace: 18453140 [on line 613 of "/var/www-test/horde/imp/lib/Folder.php"]

-----------------------------------------------------------------


I'm almost positive that the memory usage doubles temporarily for this 
function call:

           $body = str_replace("\r\n", "\n", $body);

However, I was able to avoid this memory usage penalty by calling 
str_replace within the loop on each message, rather than the entire huge 
string at the end.  This also uses less memory overall.  I suspect that 
PHP memory routines don't "cleanup" memory very well when the size of a 
variable is reduced as it is in the str_replace() call above.

I've attached a patch which implements this change.


However, it still fails if you try to download a zipped folder.  Again, 
this is probably caused by the temporary need for twice the memory in 
order to make a working copy of the folder.  Unfortunately I don't see any 
way around that.

In general, you'll need to set the PHP memory limit to twice the size of 
your largest folder download, plus some overhead (approximately 10-15MB).

 	Andy
-------------- next part --------------
--- lib/Folder.php.orig	2007-01-02 05:54:56.000000000 -0800
+++ lib/Folder.php	2007-07-17 14:12:00.000000000 -0700
@@ -596,13 +596,12 @@
                        require a space in front of single digit days. */
                     $date = sprintf('%s %2s %s', date('D M', $h->udate), date('j', $h->udate), date('H:i:s Y', $h->udate));
                     $body .= 'From ' . $from . ' ' . $date . "\n";
-                    $body .= imap_fetchheader($_SESSION['imp']['stream'], $i, FT_PREFETCHTEXT);
-                    $body .= imap_body($_SESSION['imp']['stream'], $i, FT_PEEK) . "\n";
+                    $body .= str_replace("\r\n", "\n", imap_fetchheader($_SESSION['imp']['stream'], $i, FT_PREFETCHTEXT));
+                    $body .= str_replace("\r\n", "\n", imap_body($_SESSION['imp']['stream'], $i, FT_PEEK) . "\n");
                 }
             }
         }
 
-        $body = str_replace("\r\n", "\n", $body);
         return $body;
     }
 


More information about the imp mailing list