Using apache 2.0.48
I defined tenbyte_string as the constant string "0123456789" which is 10 bytes long.
Here is a test where I used apr_pstrcat( ... ) to in a loop 10,000 iterations so the resulting string should only take up 10 * 10,000 = 100,000 bytes.
It took about 2.5 MB more than the example child by itself in redhat 7.2 this is much better than apache 1.3.29
I ran this equivalent code on apache 1.3.29 redhat version 7.2 and it used nearly 400 Mega Bytes of RAM, with physical RAM of only 128 MB
Does anybody know why this little loop uses so much RAM? Is there a problem with the way the code is written? Is it possible that apache has a pool problem?
The apache 2.0.48 source code follows:
-----------------------------------------------------------------------------------
#define tenbyte_string "0123456789"
void fun(void) { fprintf(stderr, "cannot create pool\n"); }
static int x_handler(request_rec *r) { int i; apr_pool_t *subp1, *subp2, *p = r->pool; char *s = "";
if (strcmp(r->handler, "example-handler")) { return DECLINED; }
ap_set_content_type(r, "text/html");
if (r->header_only) { return OK; }
ap_rputs(DOCTYPE_HTML_3_2, r);
ap_rputs("<HTML>\n", r);
ap_rputs(" <HEAD>\n", r);
ap_rputs(" <TITLE>mod_example Module Content-Handler Output\n", r);
ap_rputs(" </TITLE>\n", r);
ap_rputs(" </HEAD>\n", r);
ap_rputs(" <BODY>\n", r);
ap_rputs(" <H1><SAMP>mod_example</SAMP> Module Content-Handler Output\n", r);
ap_rputs(" </H1>\n", r);
ap_rputs(" <P>\n", r);
ap_rprintf(r, " Apache HTTP Server version: \"%s\"\n",
ap_get_server_version());
ap_rputs(" <BR>\n", r);
ap_rprintf(r, " Server built: \"%s\"\n", ap_get_server_built());
ap_rputs("<h1>hello world</h1><br>\n", r);
ap_rputs(" </BODY>\n", r);
ap_rputs("</HTML>\n", r);
apr_pool_create_ex(&subp1, p, fun, NULL); apr_pool_create_ex(&subp2, p, fun, NULL); for (i = 0; i < 10000; i++) { apr_pool_clear(subp1); s = apr_pstrcat(subp1, s, tenbyte_string, NULL); apr_pool_clear(subp2); s = apr_pstrdup(subp2, s); } apr_pool_destroy(subp1); apr_pool_destroy(subp2);
return OK; }
-----------------------------------------------------------------------------------
Still in apache 2.0.48
Now set the loop iterations to 20,000 the child took 11 MB total and 75 seconds Child never released the RAM till apache restarted.
Now set the loop iterations to 25,000 the child took 17 MB total and 120 seconds Child never released the RAM till apache restarted.
Now set the loop iterations to 30,000 the child took 23 MB total and 180 seconds Child never released the RAM till apache restarted.
Now set the loop iterations to 35,000 the child took 31 MB total and 250 seconds Child never released the RAM till apache restarted.
Now set the loop iterations to 100,000 the child took over 100 MB total and over 1000 seconds i killed the process before completion Child never released the RAM till apache was stopped.
Just for fun I wrote some equivalent code using calloc, strlen, strcpy, free and pstrdup. At 30,000 iterations the child took 2.2 MB and 265 seconds. Base child for mod_example was about 2 MB when child was done child RAM usage dropped back down to about 2 MB.
At 30,000 iterations: So malloc, calloc, free took about 1.5 times longer than apache. 265/180 = 1.472 but it only used a fraction of the RAM size of apache.
Conclusion: Apache 2.0.X pools are much more efficient in RAM allocation than apache 1.3.X pools and run in 2/3 the time as malloc, calloc and free.
If you are not using many iterations then you should use apache pools because they are faster. If you use very many iterations in Apache 1.3.X you will run out of RAM and bring down the server.
Also an apache child never released the RAM once it had allocated it.
--- Mark R. Rowe, MSEE