apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Karl Fogel <kfo...@newton.ch.collab.net>
Subject Re: any documentation on the point of having pools?
Date Fri, 29 Mar 2002 01:34:03 GMT
Jay,

I can partially answer your question.

Let's say there are three kinds of memory allocation in the world:

   1. raw -- you know, like C malloc() and free()
   2. pools
   3. fully garbage-collected

For the programmer, full GC is ideal.  Unfortunately, it takes time
for the GC code to figure out what's garbage and what's not, and to
free it.  Or if that phase is to be instantaneous, then there must be
lots of little bits of overhead scattered all around, since all
allocations will be required to do some GC bookkeeping.  Usually GC is
implemented with a mixture of these two strategies, but they total up
to the same penalty, speaking *very* broadly of course.

I don't want to get into one of programming's longest-running debates,
but let's just say that despite occasional claims that full GC can, in
principle, be just as efficient as "raw" allocation methods, in
practice it never has been, and looks unlikely to be so in the near
future.  There are also some issues when it comes to interacting with
non-GC'd languages, as you might expect.  Not knocking GC -- my
far-and-away favorite language is Lisp -- but GC comes with a penalty.

Anyway, APR is written in C, and that's actually an important part of
its design as a portability layer.  So full GC would be technically,
uh, difficult under the circumstances, even without considering the
performance hit. :-)

So let's look at the remaining two options: raw vs pools.

Some programmers find pools easier to work with, some prefer raw
allocation.  We'll probably never get agreement on that.

However, there is one nice thing about pools: they can fulfill the
promise that GC never did -- the promise of being more efficient than
malloc() and free().  The reason is that in raw-style allocation,
every malloc() call must have a matching free() call.  But a pool can
clean up multiple mallocs() with one free().  I'm not talking about
literal "malloc" calls, of course, but just the act of allocating
something in that pool; and by "free" I mean apr_pool_clear or
apr_pool_destroy, but you get the idea.  Pool bookkeeping is done in
such a way that you can mark the whole pool as reclaimable in one
essentially constant-time operation, independent of how many objects
(of whatever lengths) you may have allocated in that pool.

Aside from the efficiency aspect (which I suspect is not so great as
to be a major motivation, perhaps Sander or someone can comment?),
people who like pools like them because they give a convenient idiom
for expressing the lifetimes of objects.  If you have a run of code
that's going to cons up [er, excuse me, allocate] some objects, all of
which need to remain valid for the duration of a certain set of
operations, it's handy to put them all in the same pool, and just
destroy the pool at the end.  When the same code is written using raw
allocation, it usually flaunts a dozen calls to free() at the end, and
when you add a new object to that run of code, it's easy to forget to
add yet another call to free().  Note that in the pool style, it's
usually easy to see which pool you're supposed to allocate the thing
in, or at least the presence of multiple pools there will force you to
ask yourself about the object's lifetime, which malloc won't.

Wow, I can't believe I stopped coding to write this :-).  I hope it's
at least technically accurate (fixes welcome!), if not persuasive.
For the record, I like pools when I don't hate them.

-Karl

"Jay Freeman \(saurik\)" <saurik@saurik.com> writes:
> Is there any documentation anywhere that describes "why you would want to
> use pools"?  I've been using APR for over a year now in virtually all of my
> projects, and I _still_ don't get what the advantage of this pool management
> that's strewn all over my programs is.  I finally got fed up, wrote a C++
> class named "pool" (with an autocast operator for getting an apr_pool_t *
> and a destructor that destroys the pool), and have an instance of it in
> _every APR related object_ so I have something I can pass to the APR
> functions when they scream out for their precious pools :-P.  I pray at
> nights that I'm not using an insane amount of working set by doing this,
> hehe.
>
> [...]

Mime
View raw message