alan@sbi.sbi.com (Alan Zeigler) (06/20/91)
I was trying to put together a package to simplify manipulation of arrays of filehandles, arrays of arrays, etc. and am still confused on a few points. In the example in the shar below, I use a "heap" as a source of variable references which works fine; however, when I try to free all possible references to the variables, I have some problems: 1. Is there a simple way to free all references to a symbol, say `foo', rather than going through and saying: undef($foo); undef(@foo); ... reset() dosen't seem to do what I want. 2. Even if I do it the brute force way, I seem to develop a memory leak if I include: undef(&foo); I also have a more generic pass-by-reference question. When I know I'm going to be playing with *foo, I was tempted to stick a local(*foo); at the beginning of the block, but that seemed to result in a corrupted heap as the block was exited. Am I missing something? Thanks in advance, Alan Zeigler P.S.: SunOS 4.1.1, PERL 4.010 #!/bin/sh # # Run the following text with /bin/sh to create: # heap/heap.pl # heap/heaptest # heap/foo # heap/bar # if test -f heap; then echo "File, not directory, heap exists"; else if test -d heap; then :; else mkdir heap; fi if test -f heap/heap.pl; then echo "File heap/heap.pl exists"; else echo "x - extracting heap/heap.pl (Text)" sed 's/^X//' << 'SHAR_EOF' > heap/heap.pl && X;#============================================================================= X;#| @(#)heap.pl 1.1 91/06/20 SB X;#| X;#| PERL "Heap" Package X;#| X;#| A heap is a named set of variable references appropriate for X;#| manipulation in arrays of filehandles, arrays of arrays, etc. X;#| The entire set of references can be freed by name. X;#| X;#| Created 91/06/20, Alan M Zeigler, uunet!sbi!alan X;#| Arbitrage Trading/Proprietary Analytics, Salomon Brothers Asia, Tokyo X;#============================================================================= X Xpackage heap; X X;#----------------------------------------------------------------------------- X;# &heap_new($heap_name) X;# X;# Returns a new reference into the named heap. X;#----------------------------------------------------------------------------- Xsub main'heap_new { X local($heap_name) = @_; X X eval('*' . $heap_name . eval('++$' . $heap_name)); X} X X;#----------------------------------------------------------------------------- X;# &heap_reset($heap_name) X;# X;# Free all references in the named heap. X;#----------------------------------------------------------------------------- Xsub main'heap_reset { X local($heap_name) = @_; X X local(*cnt) = eval('*' . $heap_name); X local($heap_cnt); X X for (; $cnt; --$cnt) { X $heap_cnt = $heap_name . $cnt; X X # IS THERE A BETTER WAY TO FREE ALL REFERENTS? X eval(<<" EOF"); X close($heap_cnt); X closedir($heap_cnt); X dbmclose($heap_cnt); X undef(\$$heap_cnt); X undef(\@$heap_cnt); X undef(\%$heap_cnt); X # ADDING THIS INTRODUCES A MEMORY LEAK! X #undef(&$heap_cnt); X EOF X } X X eval('undef($' . $heap_name . ')'); X} X X1; SHAR_EOF chmod 0444 heap/heap.pl || echo "restore of heap/heap.pl fails" set `wc -c heap/heap.pl`;Sum=$1 if test "$Sum" != "1670" then echo original size 1670, current size $Sum;fi fi if test -f heap/heaptest; then echo "File heap/heaptest exists"; else echo "x - extracting heap/heaptest (Text)" sed 's/^X//' << 'SHAR_EOF' > heap/heaptest && X#!/usr/local/bin/perl -P X;#============================================================================= X;#| @(#)heaptest 1.1 91/06/20 SB X;#| X;#| PERL "Heap" Test X;#| X;#| Created 91/06/20, Alan M Zeigler, uunet!sbi!alan X;#| Arbitrage Trading/Proprietary Analytics, Salomon Brothers Asia, Tokyo X;#============================================================================= X Xrequire('heap.pl'); X X;# Invoke as `perl heaptest', disabling cpp, to run silent X;# and repetitively ... checking for leaks. X#if 0 Xclose(STDOUT); Xwhile ($i++ < 1000000) { X#endif X X #-------------------------------------------------------------------------- X # Heap used for array of filehandles. X #-------------------------------------------------------------------------- X X undef(@filehandle_array); X X # Open array of filehandles. X foreach ('foo', 'bar') { X *FILEHANDLE = &heap_new('filehandle_heap'); X open(FILEHANDLE, $_); X push(@filehandle_array, *FILEHANDLE); X } X X # Interleave lines of files. X do { X $more = 0; X foreach $filehandlep (@filehandle_array) { X *FILEHANDLE = $filehandlep; X ($_ = <FILEHANDLE>) && ++$more && print; X } X } while ($more); X X # Free the heap (which closes files). X &heap_reset('filehandle_heap'); X X X #-------------------------------------------------------------------------- X # Heap used for array of arrays (nested arrays). X #-------------------------------------------------------------------------- X X # Even top level array is in heap (as @filehandle_array X # could have been in the previous example). X *array_of_arrays = &heap_new('array_of_arrays_heap'); X X # Allocate and populate nested arrays. X foreach (1 .. 10) { X *array = &heap_new('array_of_arrays_heap'); X @array = $_ .. $_ + 9; X push(@array_of_arrays, *array); X } X X # Verify nested arrays. X foreach (@array_of_arrays) { X *array = $_; X print(join(' ', @array), "\n"); X } X X # Free nested array. X &heap_reset('array_of_arrays_heap'); X X X;# End of leak-test loop. X#if 0 X} X#endif SHAR_EOF chmod 0555 heap/heaptest || echo "restore of heap/heaptest fails" set `wc -c heap/heaptest`;Sum=$1 if test "$Sum" != "2066" then echo original size 2066, current size $Sum;fi fi if test -f heap/foo; then echo "File heap/foo exists"; else echo "x - extracting heap/foo (Text)" sed 's/^X//' << 'SHAR_EOF' > heap/foo && Xfoo1 Xfoo2 Xfoo3 Xfoo4 Xfoo5 Xfoo6 Xfoo7 Xfoo8 Xfoo9 SHAR_EOF chmod 0644 heap/foo || echo "restore of heap/foo fails" set `wc -c heap/foo`;Sum=$1 if test "$Sum" != "45" then echo original size 45, current size $Sum;fi fi if test -f heap/bar; then echo "File heap/bar exists"; else echo "x - extracting heap/bar (Text)" sed 's/^X//' << 'SHAR_EOF' > heap/bar && Xbar1 Xbar2 Xbar3 Xbar4 Xbar5 Xbar6 Xbar7 Xbar8 Xbar9 SHAR_EOF chmod 0644 heap/bar || echo "restore of heap/bar fails" set `wc -c heap/bar`;Sum=$1 if test "$Sum" != "45" then echo original size 45, current size $Sum;fi fi fi exit 0 -- Alan M Zeigler Arbitrage Trading/Proprietary Analytics, Salomon Brothers Asia Limited Urbannet Otemachi Bldg, 2-2, Otemachi 2-chome, Chiyoda-ku, Tokyo 100, Japan Work: 81 3 5255-4483 | FAX: 81 3 5255-5598 | E-Mail: uunet!sbi!alan
tchrist@convex.COM (Tom Christiansen) (06/20/91)
From the keyboard of alan@sbi.sbi.com (Alan Zeigler): >while ($i++ < 1000000) { > foreach ('foo', 'bar') { > *FILEHANDLE = &heap_new('filehandle_heap'); I'm not entirely surprised you're getting a leak here. From the man page: Assignment to *name is currently recommended only inside a local(). You can actually assign to *name anywhere, but the previous referent of *name may be stranded forever. This may or may not bother you. I suspect that's what happening to you. Of course, if you say local(*FILEHANDLE) in your loop, you'll still get 1000000 versions pushed on the stack, which I'd call sub-optimal. --tom -- Tom Christiansen tchrist@convex.com convex!tchrist "So much mail, so little time."