Improving mod_perl Driven Site's Performance -- Part V: Sharing Memory

By Stas Bekman (Send Email)
Posted Jan 24, 2001


Sharing Memory

As we have learned in the previous article, sharing memory helps us to save memory with mod_perl, which gives us a huge speed up, but we pay with price of big memory footprint. In this article, we will see other techniques that allow you to save even more memory, such as preloading registry scripts at server startup and initializing CGI.pm.

As we have learned in the previous article, sharing memory helps us to save memory with mod_perl, which gives us a huge speed up but we pay with price of big memory foot print. I presented a few techniques to save memory by trying to share more of it. In this article, we will see other techniques allowing you to save even more memory.

Preloading Registry Scripts at Server Startup

What happens if you find yourself stuck with Perl CGI scripts and you cannot or don't want to move most of the stuff into modules to benefit from modules preloading, so the code will be shared by the children. Luckily you can preload scripts as well. This time the Apache::RegistryLoader modules comes to aid. Apache::RegistryLoader compiles Apache::Registry scripts at server startup.

For example to preload the script /perl/test.pl which is in fact the file /home/httpd/perl/test.pl you would do the following:

  use Apache::RegistryLoader ();
  Apache::RegistryLoader->new->handler("/perl/test.pl",
                            "/home/httpd/perl/test.pl");

You should put this code either into <Perl> sections or into a startup script.

But what if you have a bunch of scripts located under the same directory and you don't want to list them one by one. Take the benefit of Perl modules and put them to a good use. The File::Find module will do most of the work for you.

The following code walks the directory tree under which all Apache::Registry scripts are located. For each encountered file with extension .pl, it calls the Apache::RegistryLoader::handler() method to preload the script in the parent server, before pre-forking the child processes:


  use File::Find qw(finddepth);
  use Apache::RegistryLoader ();
  {
    my  = "/home/httpd/perl/";
    my  = Apache::RegistryLoader->new;
    finddepth
      (
       sub {
         return unless /\.pl$/;
         my  = "::Find::dir/sh";
          =~ s|/?|/|;
         warn "pre-loading \n";
           # preload 
         my  = ->handler();
         unless( == 200) {
           warn "pre-load of '' failed, status=\n";
         }
       },
       );
  }

Note that I didn't use the second argument to handler() here, as in the first example. To make the loader smarter about the URI to filename translation, you might need to provide a trans() function to translate the URI to filename. URI to filename translation normally doesn't happen until HTTP request time, so the module is forced to roll its own translation. If filename is omitted and a trans() function was not defined, the loader will try using the URI relative to ServerRoot.

A simple trans() function can be something like that:

  sub mytrans {
    my  = shift;
     =~ s|^/perl/|/home/httpd/perl/|;
    return ;
  }

You can easily derive the right translation by looking at the Alias directive. The above mytrans() function is matching our Alias:

  Alias /perl/ /home/httpd/perl/

After defining the URI to filename translation function you should pass it during the creation of the Apache::RegistryLoader object:

  my  = Apache::RegistryLoader->new(trans => \&mytrans);

Page 1 of 6


Comment and Contribute

Your name/nickname

Your email

(Maximum characters: 1200). You have characters left.