Return-Path: Delivered-To: apmail-apr-cvs-archive@apr.apache.org Received: (qmail 76408 invoked by uid 500); 25 Jun 2003 21:50:57 -0000 Mailing-List: contact cvs-help@apr.apache.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Reply-To: dev@apr.apache.org Delivered-To: mailing list cvs@apr.apache.org Received: (qmail 76232 invoked from network); 25 Jun 2003 21:50:55 -0000 Date: 25 Jun 2003 21:50:55 -0000 Message-ID: <20030625215055.84398.qmail@icarus.apache.org> From: gstein@apache.org To: apr-cvs@apache.org Subject: cvs commit: apr/docs pool-design.html X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N gstein 2003/06/25 14:50:53 Added: docs pool-design.html Log: move serf's pool-design.txt here as part of the actual APR docs. Revision Changes Path 1.1 apr/docs/pool-design.html Index: pool-design.html =================================================================== Using APR Pools
Last modified at [$Date: 2003/06/25 21:50:16 $]

Using APR Pools

From Subversion, we have learned a lot about how to use pools in a heavily structured/object-based environment. Apache httpd is a completely different beast: "allocate a request pool. use it. destroy it."

In a complex app, that request-style of behavior is not present. Luckily, the "proper" use of pools can be described in just a few rules:

  • Objects should not have their own pools. An object is allocated into a pool defined by the constructor's caller. The caller knows the lifetime of the object and will manage it via the pool. Generally, this also means that objects will not have a "close" or a "free" since those operations will happen implicitly as part of the destruction of the pool the objects live within.
  • Functions should not create/destroy pools for their operation; they should use a pool provided by the caller. Again, the caller knows more about how the function will be used, how often, how many times, etc. Thus, it should be in charge of the function's memory usage.

    As an example, the caller might know that the app will exit upon the function's return. Thus, the function would be creating extra work if it built and destroyed a pool. Instead, it should use the passed-in pool, which the caller is going to be tossing as part of app-exit anyways.

  • Whenever an unbounded iteration occurs, a subpool should be used. The general pattern is:

      subpool = apr_create_subpool(pool);
      for (i = 0; i < n; ++i) {
        apr_pool_clear(subpool);
      
        do_operation(..., subpool);
      }
      apr_pool_destroy(subpool);

    This pattern prevents the 'pool' from growing unbounded and consuming all of memory. Note that it is slightly more optimal to clear the pool on loop-entry. This pattern also allows for a 'continue' to occur within the loop, yet still ensure the pool will be cleared.

  • Given all of the above, it is pretty well mandatory to pass a pool to every function. Since objects are not recording pools for themselves, and the caller is always supposed to be managing memory, then each function needs a pool, rather than relying on some hidden magic pool. In limited cases, objects may record the pool used for their construction so that they can construct sub-parts, but these cases should be examined carefully. Internal pools can lead to unbounded pool usage if the object is not careful.

Greg Stein
Last modified: Wed Jun 25 14:50:19 PDT 2003