Perl:在没有超出范围的情况下,何时不需要释放标量的内存?

Tho*_*ing 12 memory perl memory-management

我有一个应用程序,它将大量的文本数据读入标量,有时甚至是GB.我substr在该标量上使用将大部分数据读入另一个标量并用空字符串替换提取的数据,因为在第一个标量中不再需要它.我最近发现的是,Perl并没有释放第一个标量的内存,而是认识到它的逻辑长度发生了变化.所以我需要做的是将数据从第一个标量再次提取到第三个undef标量,第一个标量并将提取的数据放回原位.只有这样,第一个标量所占用的内存才能真正释放出来.将undef分配给该标量或小于分配的内存块的其他值不会改变有关分配的内存的任何信息.

以下是我现在所做的事情:

     $$extFileBufferRef = substr($$contentRef, $offset, $length, '');
     $length            = length($$contentRef);
  my $content           = substr($$contentRef, 0, $length);
     $$contentRef       = undef( $$contentRef) || $content;
Run Code Online (Sandbox Code Playgroud)

$$contentRef在第一行中可能是例如5 GB的大小,我提取了4 GB的数据并替换了提取的数据.第二行现在将报告例如100 MB的数据作为字符串的长度,但是例如Devel::Size::total_size仍将输出为该标量分配的5 GB数据.并且分配undef或者这样$$contentRef似乎没有改变这一点,我需要undef在该标量上调用函数.

我本以为应用$$contentRef之后已经至少部分释放了后面的内存substr.似乎并非如此......

那么,如果变量超出范围,是否只释放内存?如果是这样,为什么在同一个标​​量上分配undef不同的调用undef作为函数?

ike*_*ami 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.
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

逻辑是,如果你需要一次记忆,你很有可能再次需要记忆.

出于同样的原因,分配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.
Run Code Online (Sandbox Code Playgroud)