如何在Perl中释放内存?

如何在Perl中释放内存?,perl,garbage-collection,Perl,Garbage Collection,我的代码如下所示: my %var; my %var_new={}; while(1){ while(my ($k,$v)=each %var){ &a_sub($v); } %var={}; # A map { $var{$_}=$var_new{$_}; } keys %var_new; %var_new={}; # B } sub a_sub { #....} # will fill %var_

我的代码如下所示:

 my %var;
 my %var_new={};

 while(1){
     while(my ($k,$v)=each %var){
            &a_sub($v);
     }
     %var={}; # A
     map { $var{$_}=$var_new{$_}; } keys %var_new;
     %var_new={}; # B
 }

 sub a_sub { #....} # will fill %var_new
我的程序的内存使用率越来越高

Perl似乎没有在A行和B行释放内存


如何手动使Perl释放已使用的内存
%var
%var\u new

我认为使用
undef
函数:

undef %var, %var_new;
也许能奏效。
当然,如果您不再需要那些散列中的内容

如果您使用了
严格
警告
,您会看到:

在预期大小为偶数的列表中找到引用

第A行和第B行并不像你想象的那样。实际上,它们将引用的字符串化版本指定为一个键,并将undef指定为其值。即使散列现在几乎为空,内存也不会被标记为可重用,因为您没有为此使用正确的语句

尝试在A行和B行使用以下语句之一:

undef %var; # this one
%var = ();  # or this one

IIRC,一旦Perl从操作系统分配了内存,它就会在进程生命周期中保留该内存。在可能的情况下,Perl将重用已经分配的内存,而不是要求操作系统提供更多的内存,但是您不会看到进程使用的内存减少。

可以通过
undef
将内存释放回操作系统。但是,
$var=undef
未定义($var)

$var=undef除了重置对象的标志外,不执行任何操作。大小还是一样

undf($var)
确实删除了指针并释放了该对象的内存-当且仅当这是“原始”变量时

有一个有趣的故事

例如,调用
unde
(在Perl 5.30.0 Fedora 31、libc 2.30上测试)之后,下面的代码几乎回到了它最初的内存使用情况

即使遍历结构并对每个元素调用
unde
,也是不够的(嵌套结构也是如此,您可以递归遍历它们,但不会有什么不同)

为什么??因为我们没有删除原始的
$skilly
。将内存返回操作系统的唯一方法是调用
unde($skelky)

如果像这样将
$skilly
的引用放入
%hash
中,
$hash{large\u string\u inside}=\$skilly

您仍然需要调用
undef($skilly)
而不是
undef($hash{large\u string\u inside})

为什么要将hashref分配给hash?
使用strict;使用警告;使用diagnostics
(仅在开发过程中使用后者)尽管您发布的代码中存在bug,但没有理由让您发布的代码使用越来越多的内存,我认为这与其说是内存使用的问题,不如说是你已经建立了一个无限循环,从中没有逃逸。将
%var
%var\u new
设置为
{}
应该有同样的效果。事实并非如此。使用Devel::Peek进行检查。@KeithThompson否,将
%var
%var\u new
设置为
()
应具有相同的效果。取消定义散列将释放内存供perl进程内的其他用途,但不会减少进程使用的总内存。@chepner不正确。这完全取决于散列中的内容。如果不使用任何变量来填充哈希,例如
$hash{thing}=“A”x 10000000它将释放所有内存,并将内存返回操作系统。然而,如果你想做
$hash{thing}=$var
,只有散列本身是免费的,但是由于
$var
仍然是免费的,内存使用率可能会几乎保持不变。你所说的在实践中是正确的,但是Perl实际上可以将内存返回给操作系统。另一个问题是,在一般情况下,这是否可取。如何强制将未使用的内存释放到操作系统?是的。一旦一个进程从操作系统分配内存,它将一直保留到生命的尽头。它适用于任何语言,而不仅仅是Perl。也就是说,它编译Perl是为了使用mmap而不是它自己的malloc,只要内存完全未使用,就可以释放内存。@Luchostein,恕我直言,这不是真的<代码>perl-e'$a=“a”x100\u 000\u 000;对于(1..10){push@b,“$\$a”}睡眠10@b=();睡100;'这将使用>1GB 10秒,然后再删除
#!perl

use feature 'say';

say "PID: $$";
say "Before Alloc";
<STDIN>;

my $large_string = "A" x 100000000;

say "After Alloc - Before undef";
<STDIN>;

undef($large_string);

say "After undef";
<STDIN>;
#!perl

use feature 'say';
use Devel::Peek;
$Devel::Peek::pv_limit = 15;

say "PID: $$";
say "BEFORE ALLOC";
<STDIN>;

my $sneaky = "A" x 100000000;
my %hash;
$hash{large_string_inside} = $sneaky;

say "After Alloc - Before undef";
say '$sneaky:';
Dump($sneaky);

say '%hash:';
Dump(%hash);

<STDIN>;

undef(%hash);

say "After undef";

say '$sneaky:';
Dump($sneaky);


say '%hash:';
Dump(%hash);

<STDIN>;
while(my ($k, $v) = each %hash) {
    undef($v); # THIS IS NOT ENOUGH
}