Perl:什么时候释放不需要的标量内存而不超出范围?

标签 perl memory 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;

$$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/

相关文章:

perl - 按内部哈希值对哈希数组的哈希进行排序

perl - 如何在 Windows 上的 Perl 中将具有 UTF-8 文件名的文件复制到另一个 UTF-8 文件名?

.net - 在 .NET 中处理大量内存对象

perl - 如何抽象多个嵌套循环?

windows - 如何使用 Perl 快速修复大文件中的 EBCDIC 控制字符?

c++ - 使用 C++ 释放内存

c++ - 内存管理不好?大于 1 的类成员( bool )值,在递归函数中

native 进程的 Java 内存使用情况

java - 在循环期间动态写入 CSV

c - C 中全局/局部变量的内存对齐