为什么符号的封装限定会导致使用更少的内存,即使符号是本地导入的?

Eva*_*oll 6 perl symbols package microbenchmark

请注意,我之前尝试在此问题中对此进行测试,这可能看起来相似,但是这些结果存在缺陷并且是不断折叠结果,我随后将其禁用。并在此问题中重新发布。


鉴于这两个 evals(评论一个关于执行)只改变&Module::FOO()&FOO()

# Symbols imported, and used locally.
eval qq[ 
  package Foo$num;
  Module->import();
  my \$result = &Module::FOO() * &Module::FOO();
] or die $@;

# Symbols imported, not used locally referencing parent symbol.
eval qq[ 
  package Foo$num;
  Module->import();
  my \$result = &FOO() * &FOO();
] or die $@;
Run Code Online (Sandbox Code Playgroud)

为什么会顶块占据显着更少的空间?脚本和输出复制如下,

脚本

package Module {
  use v5.30;
  use warnings;
  use constant FOO => 42; 
  use Exporter 'import';
  our @EXPORT = ('FOO');
}


package main {
  use v5.30;
  use autodie;
  use warnings;

  $|=1;
  say "Our PID is $$";

  for my $num ( 0..1e5 ) { 
    eval qq[ 
      package Foo$num;
      Module->import();
      my \$result = &Module::FOO() * &Module::FOO();
    ] or die $@;
    eval qq[
      package Foo$num;
      Module->import();
      my \$result = &FOO() * &FOO();
    ] or die $@;
  }

  say "DONE";

  _debug();

}

sub _debug {
  open my $fh, "<", "/proc/$$/status";
  while ( <$fh> ) { 
    next unless /Rss/;
    print;
  }
}
Run Code Online (Sandbox Code Playgroud)

结果

包(命名空间)限定

RssAnon:     101856 kB
RssFile:       5228 kB
RssShmem:         0 kB
Run Code Online (Sandbox Code Playgroud)

本地进口

RssAnon:     151528 kB
RssFile:       5224 kB
RssShmem:         0 kB
Run Code Online (Sandbox Code Playgroud)

更新

aquanighton要求直接irc.freenode.net/#perl尝试这个实验constant,这是我使用的代码,

eval qq[ 
  package Foo$num;
  use constant FOO => 42;
  my \$result = &FOO() * &FOO();
] or die $@; 
eval qq[ 
  package Foo$num;
  use constant FOO => 42;
  my \$result = &Foo${num}::FOO() * &Foo${num}::FOO();
] or die $@;
Run Code Online (Sandbox Code Playgroud)

有了这两个示例,要清楚,直接使用带有常量的变体并通过包限定访问常量实际上更糟糕,然后创建另一个包,该包具有常量 to 和 package-qualify 到那个包裹。

Our PID is 204846
RssAnon:     143560 kB
RssFile:       5196 kB
RssShmem:         0 kB
Run Code Online (Sandbox Code Playgroud)

Eva*_*oll 4

导出整个符号

如果导出整个符号而不是全局中的一个插槽,似乎可以非常接近,

our @EXPORT = ('*FOO');
Run Code Online (Sandbox Code Playgroud)

重新运行相同的测试,你会发现两者非常相似

RssAnon:      93900 kB
RssFile:       5228 kB
RssShmem:         0 kB
Run Code Online (Sandbox Code Playgroud)

事实上,这更接近理论最大值,这完全不需要调用import

eval qq[
  package Foo$num;
  my \$result = &Module::FOO() * &Module::FOO();
] or die $@;
Run Code Online (Sandbox Code Playgroud)

从而产生,

RssAnon:      74528 kB
RssFile:       5160 kB
RssShmem:         0 kB
Run Code Online (Sandbox Code Playgroud)

也许,最大的黑魔法快乐。

然而,如果我们按照 所建议的那样检查这块荣耀aquanight

our sub FOO;      # top of file
Module->import();

package Bar;
print FOO();      # works
print Bar::FOO(); # does not work
Run Code Online (Sandbox Code Playgroud)

该符号FOO可用于打包Bar,而不会导致包膨胀Bar。当将此方法应用于上述基准测试时,看起来像:

eval qq[
  our sub FOO ();
  Module->import();
  package Foo$num;
  my \$result = FOO() * FOO();
] or die $@;
Run Code Online (Sandbox Code Playgroud)

并产生这些结果,

RssAnon:      75112 kB
RssFile:       5284 kB
RssShmem:         0 kB
Run Code Online (Sandbox Code Playgroud)

constant.pm

这可以进一步实现为,

eval qq[
  our sub FOO ();
  use constant FOO => 42;
  package Foo$num;
  my \$result = FOO() * FOO();
];
Run Code Online (Sandbox Code Playgroud)

这会产生这些结果,

RssAnon:      75076 kB
RssFile:       5180 kB
RssShmem:         0 kB
Run Code Online (Sandbox Code Playgroud)