我有一个应用程序,它可以将大量文本数据读入一个标量,有时甚至是 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.9 GB 的数据并替换了提取的数据。第二行现在将报告例如100 MB 的数据作为字符串的长度,但例如Devel::Size::total_size
仍会输出为该标量分配的 5 GB 数据。并且将 undef
或诸如此类分配给 $$contentRef
似乎并没有改变这一点,我需要将 undef
作为函数调用那个标量。
我原以为 $$contentRef
后面的内存在应用 substr
后已经至少部分释放了。好像不是这样的……
那么,只有在变量超出范围时才释放内存吗?如果是这样,为什么分配 undef
不同于调用 undef
作为同一标量上的函数?
最佳答案
你的分析是正确的。
$ 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.
关于Perl:什么时候释放不需要的标量内存而不超出范围?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39513307/