I believe that I have made some progress on this, but I'm not confident
that my solution is the correct one.  There were several factors playing
into this that pulled my attention away from the real issue.

I originally reported that this problem was CGI specific; it turns out
that this is not the case.  The way I was reproducing what appeared to be
a major leak was by sending a number of parallel requests to CGIs that
generate a lot of output.  The result of this was that Apache needed a lot
of temporary buffers at the same time.  After digging around for a while,
I discovered that Apache on Windows never calls
apr_allocator_max_free_set(), and the default behaviour is to hold on to
all memory ever allocated, and allocate memory future requests out of that
block.  When I spawned the parallel requests, Apache grabbed a whole bunch
of memory, and then kept reusing it.  After setting a limit here, I was
able to move on to the bigger problem.

After making the change above, I realized that every request was leaking a
little bit, not just the CGI requests.  To confirm this, I made a simple
configuration file that redirects all requests to a static HTML file.
Sure enough, it was leaking.

The problem, as best as I can tell, is that mpm_winnt calls
apr_bucket_alloc_create() once for each thread, and registers it in the
pchild pool.  This bucket allocator is then passed through to
core_create_conn(), and used for all apr_bucket_XXX() routines during the
request.  The pchild pool is not cleared until the server shuts down, so
the memory used here grows and grows.  To solve this problem I changed
mpm_winnt so that it creates the bucket allocator using the ptrans pool,
which gets cleared after every connection is finished.

After making this change, the system behaved much better.  Just to check,
I then undid my first change related to the maximum memory to hold on to,
and the system continued to function corrrectly.  So in the end, I only
needed the one fix.

The following patch shows the changes I made.  My question now for the
experts is whether this will break anything.

Thanks,
Alex.

Index: server/mpm/winnt/child.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/winnt/child.c,v
retrieving revision 1.9
diff -u -u -r1.9 child.c
--- server/mpm/winnt/child.c    14 Oct 2002 14:54:45 -0000      1.9
+++ server/mpm/winnt/child.c    20 Dec 2002 01:02:38 -0000
@@ -122,6 +122,7 @@
     if (context) {
         apr_pool_clear(context->ptrans);
         context->next = NULL;
+        context->ba = apr_bucket_alloc_create(context->ptrans);
         ResetEvent(context->Overlapped.hEvent);
         apr_thread_mutex_lock(qlock);
         if (qtail)
@@ -187,7 +188,7 @@
         apr_pool_tag(context->ptrans, "ptrans");

         context->accept_socket = INVALID_SOCKET;
-        context->ba = apr_bucket_alloc_create(pchild);
+        context->ba = apr_bucket_alloc_create(context->ptrans);
         apr_atomic_inc(&num_completion_contexts);
     }

@@ -416,7 +417,7 @@
         context = apr_pcalloc(pchild, sizeof(COMP_CONTEXT));
         apr_pool_create(&context->ptrans, pchild);
         apr_pool_tag(context->ptrans, "ptrans");
-        context->ba = apr_bucket_alloc_create(pchild);
+        context->ba = apr_bucket_alloc_create(context->ptrans);
     }

     while (1) {


Reply via email to