in reply to Memory usage double expected
#!/usr/bin/perl -w use strict; use warnings; sub myfunc_1 { my $A = ''; vec($A, 20000000, 8) = 0; return $A; } sub myfunc_2 { vec($_[0], 100000000, 8) = 0; return 0; } $b = <STDIN>; my $BIGSTRING = ''; myfunc_2($BIGSTRING); # memory usage is normal. $b = <STDIN>; undef $BIGSTRING; # Pff! Gone from memory! TINYPERL.EXE memory # usage visibly shrinks in Windows Task Manager. $b = <STDIN>; my $STRING2 = myfunc_1(); # memory usage is double! $b = <STDIN>; undef $STRING2; # Deletes one copy only $b = <STDIN>;
CONCLUSION: If you write a sub that reads something, let's say, you write a sub called ReadFile() you don't want to return the contents of the file as the return value of the sub, because then two copies of the data will exist in memory. You pass the buffer as an argument to the sub, and then the sub fills it up using
$_[1] = 'CONTENT';
Perhaps this is why sysread() also works the same way; instead of returning the bytes that were read from the file, it expects the buffer to be passed to it as an argument. The first argument is the file handle, the second is the buffer and the third is the number of bytes to read. And it returns the number of bytes that were read instead of the actual bytes!
ALSO NOTE: Even if your sub does not spell out "return $BIGSTRING;" it still returns the multi-megabyte string if that was the return value of the last statement in the sub. And even if you do not use the return value of the sub, it still gets stuck in memory!!!
#!/usr/bin/perl -w use strict; use warnings; sub MemoryEaterFunc { my $A = ''; vec($A, 20000000, 8) = 0; # Create a large string $A .= $_[0]; # Add to it. Do something. # Evaluate the last statement, # and that is the return value of the sub! even if # you don't write return $A; it still returns it. # If you want the function to not return the big string, # then put 'return 0;' at the end of the sub. } $a = <STDIN>; MemoryEaterFunc(2); # Eats memory and doesn't release it $a = <STDIN>;
You say, "All right fine! I will return zero and then see what happens!"
Unfortunately, the MemoryEaterFunc() will still gobble up 20 megabytes of RAM even if it returns zero, and you do not use its return value. To actually make sure that it doesn't gobble up memory, we need to undef the variable $A before exiting the sub!
Interestingly, if you do not undef $A and you use that same sub repeatedly, it doesn't gobble up an additional 20 MB EACH time. It only uses 20 MB total. Period. (In a way, this proves that Perl uses heap memory instead of stack.)
MemoryEaterFunc(2);
MemoryEaterFunc(2);
MemoryEaterFunc(2);
MemoryEaterFunc(2);
# At this point, memory usage is 20 MB.
$b = <STDIN>;
Okay, so let's fix this thing so it doesn't waste memory anymore:
sub MemoryEaterFunc_FIXED { my $A = ''; vec($A, 20000000, 8) = 0; # Create a large string $A .= $_[0]; # Add to it. Do something. undef $A; }
Now the memory eater doesn't eat memory anymore. It uses 20 MB of memory INSIDE the sub, but then once it gets done, it no longer holds onto that memory.
|
|---|