http://qs321.pair.com?node_id=413831

shay has asked for the wisdom of the Perl Monks concerning the following question:

I have a perl source code filter module, written in XS/C, which contains a BOOT: section that allocates some memory using Newz() and an END subroutine that frees it using Safefree().

This works fine in "normal usage", and under CGI, but under mod_perl it breaks because the BOOT: is only run once but the END is run at the end of each request (since the filter module is necessarily pulled in during the loading of the script to be filtered, rather than preloaded via PerlModule during the server startup). Hence multiple requests end up multiply repeatedly free()'ing space that has long since already been free()'d at the end of the first request. Not good.

The question is: What can I do to solve this? Ideally I would like a solution that will work within the filter module itself, rather than requiring the users of the module to do extra stuff, and it must also work in non-mod_perl usage too.

The simplest solution is to just delete the END subroutine. The space allocated in BOOT: will get returned to the OS when the process exits anyway, so do I even need to be free()'ing it explicitly?

Can anyone see any problem with not bothering to do the free()'s at all?

Is there another solution besides just omitting the END sub? I couldn't see any counterpart to BOOT: in the perlxs manpage, and DESTROY is no good since it is only called for objects, not packages/classes.

- Steve

  • Comment on Do I need to free allocated space in an END sub?

Replies are listed 'Best First'.
Re: Do I need to free allocated space in an END sub?
by Joost (Canon) on Dec 10, 2004 at 16:08 UTC
    Your problem isn't with mod_perl per se, but with Apache::Registry - it calls END blocks at the end of each request, probably to accomodate sloppy coding :-)

    Maybe you could put an object in a global at BOOT time, and hang a DESTROY method on that object. As long as you don't remove the object during normal runtime, it should be destroyed when the interpreter exits (and DESTROY should be called then).

    For other options, see Apache::ChildExit.

      If BEGIN is not called for each request then how the come END is?

      I mean going by the logic that the BEGIN is only executed once when the script is loaded into memory, I would assume that the END is also only executed once when it leaves memory i.e the interpreter ends not the request.

      that'll teach me to assume eh. regarding your problem I think you are probably right perls own garbage collection will hopefully save you the bother. .... This was annoying me, so google yielded this understanding mod_perl environments
        If BEGIN is not called for each request then how the come END is?

        I think the reason is, that Apache::Registry is meant to make it easy to run CGI scripts as mod_perl scripts. Since END blocks in CGI scripts are run after each request, they also run after each request when using Apache::Registry. I don't like it either, but apparantly, that's how it is.

        As for BEGIN blocks: if you really want to run them at the right time, you'd have to remove all the loaded code and variables from the interpreter before handling the request (and then reload all the code) - it would probably make Apache::Registry scripts almost as slow as normal CGI scripts.

        Did you mis-read? I have a BOOT: section (an XS keyword), not a BEGIN sub.

        END is called for each request if the module was loaded by the Apache child process. If it is preloaded by the server process (e.g. PerlModule line in the httpd.conf file) then the END is only run once when the server shuts down. This is fine, except that it isn't possible for a source filter module, which, as I said, is necessarily loaded by the child when loading the script.

        Unless, of course, you have the server pre-load the script (?)

        Anyway, I wanted a more "natural" solution that doesn't require the user to have loaded the script/module at some particular time.

      Having an object to DESTROY seems like a neat idea, so I'll try that.

      Thanks

Re: Do I need to free allocated space in an END sub?
by gmpassos (Priest) on Dec 11, 2004 at 00:46 UTC
    If you are using END just to free the memory you don't need because after call END (in a normal Perl process) we have the global destruction, where everything will be destroied and cleaned.

    The usage of end is only needed if you need to make some operations like save things to a file, unlock DB tables, etc... So, is only needed for things that will still exists after the process be dead, in other words, only metters for things outside of your process.

    Graciliano M. P.
    "Creativity is the expression of liberty".

Re: Do I need to free allocated space in an END sub?
by blahblahblah (Priest) on Dec 11, 2004 at 15:28 UTC
    I think that in mod_perl 2 the END block doesn't get run at the end of every request -- it only runs when the process ends. So if upgrading your apache/mod_perl is an option, that might solve your problem.

    -Joe