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

I create an array @rows, with over 1000 lines of on the fly table rows. Each element of @rows is created with:

push @rows,Tr(td([$cell1,$cell2,....$cell6]));

If I then use the table function to output to a filehandle:

print FH table(@rows)

the in core script memory usage jumps to over 120 mbytes. If I use the the following:

print FH '<TABLE>',@rows,'</TABLE>';

the in core usage is about 20 mbytes. I found the same behaviour using the div function. I have only tried this on winXP, but the speed and resources saved by doing it without the fuction call is significant. Has anyone seen this, and if so was there a solution?

20060906 Janitored by Corion: Added formatting, code tags, as per Writeup Formatting Tips

Replies are listed 'Best First'.
Re: CGI.pm table function memory usage
by Fletch (Bishop) on Sep 06, 2006 at 20:17 UTC

    "Doctor, it hurts when I do this . . ."

    Unless there's a really compelling reason to do so, why not just print out the rows directly rather than building a frelling huge array in memory? You can call start_table and end_table if you feel uncomfortable hardcoding '<TABLE>' tags (I wouldn't, but . . .).

    Update: You of course need to do use CGI qw( *table ) to get these generated; the standard imports don't autogenerate them by default.

Re: CGI.pm table function memory usage
by mreece (Friar) on Sep 06, 2006 at 20:57 UTC
    fwiw, it is a little faster if you use the OO interface.
    use CGI; # ... print FH CGI->table(@rows);
    this speeds up the CGI::self_or_default, which, under use CGI qw(:standard); mode, instantiates a new CGI object for each function call.

    as for memory consumption, you'll have to work a row at a time..

    print FH CGI->start_table; print FH @rows; print FH CGI->end_table;
    (updated to clarify: it is the stringification of "@result" that CGI->table() does that is the resource killer. you can avoid that with print FH CGI->start_table, @rows, CGI->end_table;)
      ...and on top of that, instead of pushing all those table rows into @rows and then printing the whole array, you can be a little bit gentler on your memory by just printing the rows as you go like this:
      print FH CGI->start_table; for(whatever){ print FH CGI->Tr(CGI->td(...)) } print FH CGI->end_table;


      --isotope
Re: CGI.pm table function memory usage
by DrWhy (Chaplain) on Sep 06, 2006 at 20:16 UTC
    By a solution, I assume you mean is there a way to use the table() and div() functions without the memory jump. I'm not familiar much with the internals of CGI.pm, but I suspect the memory usage is due to a copy of the data being made in the function call. Each Tr(td(blah)) call creates a string. Then the table(@rows) call copies all those strings into a bigger string which it then returns. Your alternative skips the creation of the intermediate variable and just prints the existing pieces individually. If my understanding is correct. Then your second example is in fact a solution. If you really want to get the output of the table() function, you could do something like the following:
    • Get your @rows like you already do
    • Call table(), giving it a known short junk string as the data, e.g. table('<tr><td></td></tr>').
    • Split the output of the table() function on this junk string. You should get two items, the beginning and ending table tags and any associated attributes or other acoutrements.
    • Then print directly to your file handle the table start portions, your @rows, and the table end portion.

    --DrWhy

    "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

Re: CGI.pm table function memory usage
by alw (Sexton) on Sep 06, 2006 at 20:34 UTC
    You're both right. I guess only Lincoln Stein would care about the efficiency of these functions. Thanks for the comments.