我有一个应用程序,它将大量的文本数据读入标量,有时甚至是GB。我在该标量上使用substr
将大部分数据读入另一个标量,并用空字符串替换提取的数据,因为在第一个标量中不再需要它。我最近发现的是,Perl并没有释放第一个标量的内存,而是认识到它的逻辑长度已经改变了。所以我需要做的是再次将数据从第一个标量提取到第三个标量,undef
第一个标量并将提取的数据放回原位。只有这样,第一个标量所占用的内存才能真正释放出来。将undef分配给该标量或小于分配的内存块的其他值不会改变分配的内存。
以下是我现在所做的事情:
$$extFileBufferRef = substr($$contentRef, $offset, $length, '');
$length = length($$contentRef);
my $content = substr($$contentRef, 0, $length);
$$contentRef = undef( $$contentRef) || $content;
$$contentRef
可能是在第一行中大小为5 GB,我提取了4 GB的数据并替换了提取的数据。第二行现在将报告,例如100 MB的数据作为字符串的长度,但是例如Devel::Size::total_size
仍将输出为该标量分配的5 GB数据。将undef
或类似内容分配给$$contentRef
似乎没有改变这一点,我需要将undef
作为该标量的函数调用。
我原本预计在$$contentRef
应用后,substr
后面的内存已经至少部分释放了。似乎并非如此......
那么,如果变量超出范围,是否只释放内存?如果是这样,为什么分配undef
与调用undef
不同,作为同一标量的函数?
答案 0 :(得分:13)
您的分析是正确的。
$ perl -MDevel::Peek -e'
my $x; $x .= "x" for 1..100;
Dump($x);
substr($x, 50, length($x), "");
Dump($x);
'
SV = PV(0x24208e0) at 0x243d550
...
CUR = 100 # length($x) == 100
LEN = 120 # 120 bytes are allocated for the string buffer.
SV = PV(0x24208e0) at 0x243d550
...
CUR = 50 # length($x) == 50
LEN = 120 # 120 bytes are allocated for the string buffer.
Perl不仅会对字符串进行全面分配,甚至不会释放超出范围的变量,而是在下次输入范围时重复使用它们。
$ perl -MDevel::Peek -e'
sub f {
my ($set) = @_;
my $x;
if ($set) { $x = "abc"; $x .= "def"; }
Dump($x);
}
f(1);
f(0);
'
SV = PV(0x3be74b0) at 0x3c04228 # PV: Scalar may contain a string
REFCNT = 1
FLAGS = (POK,pPOK) # POK: Scalar contains a string
PV = 0x3c0c6a0 "abcdef"\0 # The string buffer
CUR = 6
LEN = 10 # Allocated size of the string buffer
SV = PV(0x3be74b0) at 0x3c04228 # Could be a different scalar at the same address,
REFCNT = 1 # but it's truly the same scalar
FLAGS = () # No "OK" flags: undef
PV = 0x3c0c6a0 "abcdef"\0 # The same string buffer
CUR = 6
LEN = 10 # Allocated size of the string buffer
逻辑是,如果你需要一次记忆,你很有可能再次需要记忆。
出于同样的原因,将undef
分配给标量不会释放其字符串缓冲区。但是Perl让你有机会释放缓冲区,所以将标量传递给undef
会强制释放标量的内部缓冲区。
$ perl -MDevel::Peek -e'
my $x = "abc"; $x .= "def"; Dump($x);
$x = undef; Dump($x);
undef $x; Dump($x);
'
SV = PV(0x37d1fb0) at 0x37eec98 # PV: Scalar may contain a string
REFCNT = 1
FLAGS = (POK,pPOK) # POK: Scalar contains a string
PV = 0x37e8290 "abcdef"\0 # The string buffer
CUR = 6
LEN = 10 # Allocated size of the string buffer
SV = PV(0x37d1fb0) at 0x37eec98 # PV: Scalar may contain a string
REFCNT = 1
FLAGS = () # No "OK" flags: undef
PV = 0x37e8290 "abcdef"\0 # The string buffer is still allcoated
CUR = 6
LEN = 10 # Allocated size of the string buffer
SV = PV(0x37d1fb0) at 0x37eec98 # PV: Scalar may contain a string
REFCNT = 1
FLAGS = () # No "OK" flags: undef
PV = 0 # The string buffer has been freed.