linux - 当子进程接触变量元数据时,如何防止内存爆炸?

标签 linux performance perl memory-management

Linux 使用 COW为了在 fork 之后保持低内存使用率,但是 Perl 5 变量在 perl 中的工作方式似乎破坏了这种优化。例如,对于变量:

my $s = "1";

perl 是真正的存储:

SV = PV(0x100801068) at 0x1008272e8
  REFCNT = 1
  FLAGS = (POK,pPOK)
  PV = 0x100201d50 "1"\0
  CUR = 1
  LEN = 16

当您在数字上下文中使用该字符串时,它会修改表示数据的 C struct:

SV = PVIV(0x100821610) at 0x1008272e8
  REFCNT = 1
  FLAGS = (IOK,POK,pIOK,pPOK)
  IV = 1
  PV = 0x100201d50 "1"\0
  CUR = 1
  LEN = 16

字符串指针本身并没有改变(它仍然是0x100201d50),但现在它在一个不同的C struct(一个PVIV而不是 PV)。我根本没有修改值,但是突然我在支付 COW 成本。有什么方法可以锁定 Perl 5 变量的 perl 表示,以便节省时间(perl 不必转换 "0"0 第二次)hack 不会影响我的内存使用吗?

请注意,上面的表示是从这段代码生成的:

perl -MDevel::Peek -e '$s = "1"; Dump $s; $s + 0; Dump $s'

最佳答案

到目前为止,我找到的唯一解决方案是确保我强制 perl 执行我期望在父进程中进行的所有转换。你可以从下面的代码中看出,即使这样也只有一点点帮助。

结果:

Useless use of addition (+) in void context at z.pl line 34.
Useless use of addition (+) in void context at z.pl line 45.
Useless use of addition (+) in void context at z.pl line 51.
before eating memory
used memory: 71
after eating memory
used memory: 119
after 100 forks that don't reference variable
used memory: 144
after children are reaped
used memory: 93
after 100 forks that touch the variables metadata
used memory: 707
after children are reaped
used memory: 93
after parent has updated the metadata
used memory: 109
after 100 forks that touch the variables metadata
used memory: 443
after children are reaped
used memory: 109

代码:

#!/usr/bin/perl

use strict;
use warnings;

use Parallel::ForkManager;

sub print_mem {
    print @_, "used memory: ", `free -m` =~ m{cache:\s+([0-9]+)}s, "\n";
}

print_mem("before eating memory\n");

my @big = ("1") x (1_024 * 1024);

my $pm = Parallel::ForkManager->new(100);

print_mem("after eating memory\n");

for (1 .. 100) {
    next if $pm->start;
    sleep 2;
    $pm->finish;
}

print_mem("after 100 forks that don't reference variable\n");

$pm->wait_all_children;

print_mem("after children are reaped\n");

for (1 .. 100) {
    next if $pm->start;
    $_ + 0 for @big; #force an update to the metadata
    sleep 2;
    $pm->finish;
}

print_mem("after 100 forks that touch the variables metadata\n");

$pm->wait_all_children;

print_mem("after children are reaped\n");

$_ + 0 for @big; #force an update to the metadata

print_mem("after parent has updated the metadata\n");

for (1 .. 100) {
    next if $pm->start;
    $_ + 0 for @big; #force an update to the metadata
    sleep 2;
    $pm->finish;
}

print_mem("after 100 forks that touch the variables metadata\n");

$pm->wait_all_children;

print_mem("after children are reaped\n");

关于linux - 当子进程接触变量元数据时,如何防止内存爆炸?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2975375/

相关文章:

c++ - 有没有办法在 C++/Linux 中重用套接字地址

ruby-on-rails - 慢资源 ruby​​ 1.9.3、macos、rails 3.2

mysql - Perl/DBIx::Class::Schema::Loader 后缀 _2 以复制关系名称

performance - 随机微分方程的疯狂空间分配求解系统

java - 我无法理解这个 MediaPlayer 错误 : MediaPlayerNative: stop called in state 0, mPlayer(0x7efba92280)

c++ - 是否有用于 C 和/或 C++ 的数据库访问库,其接口(interface)与 Perl 的 DBI 类似?

regex - 有没有办法使用正匹配正则表达式运算符对字符串进行负匹配?

linux - Perf 工具统计输出 : multiplex and scaling of "cycles"

regex - 仅当匹配 X 时,才使用 sed 从字符串中删除前 N 个和最后 N 个字符

c++ - Linux下访问打印机的最佳方法