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!alantchrist@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."