在循环中调用时,“我的”是否覆盖内存?

时间:2009-08-31 09:01:14

标签: perl memory-management variables

一个简单但相关的问题:在循环中调用时,“我的”是否覆盖内存? 例如,在循环之外声明它是“更好”(就内存泄漏,性能,速度而言):

my $variable;
for my $number ( @array ) {
    $variable = $number * 5;
    _sub($variable);   
}

或者我应该在循环中声明它:

for my $number ( @array ) {
    my $variable = $number * 5;
    _sub($variable);
}

(我刚刚编写了代码,它并不意味着做任何事情也不会被使用 - 就像它在现实生活中一样)
Perl会为每个 for 迭代在内存中分配一个新空间吗?

5 个答案:

答案 0 :(得分:9)

Aamir已经告诉过你会发生什么。

除非有理由使用第一个版本,否则我建议坚持使用第二个版本。您不想关心$variable的先前状态。使用新变量开始每次迭代最简单。如果变量包含引用,那么如果将其推送到数组上,则实际上可能shoot yourself in the foot

编辑:

是的,性能受到了打击。使用循环变量会更快。但是,它会变得多快,因为这将取决于您的具体情况。不管它有多快,但请记住:Premature optimization is the root of all evil

答案 1 :(得分:3)

从上面的例子中可以看出:

  1. 每次都不会分配变量的新空间,将使用前一个空格。

  2. 将为循环的每次迭代分配一个新空间,并在同一次迭代中对其进行解除分配。

答案 2 :(得分:3)

这些是你不应该用动态语言如Perl考虑的事情。即使你可能得到关于当前实现的回答,但这不是一个功能,它不是你应该依赖的东西。

尽可能在最短的范围内定义变量。

然而,仅仅是好奇,您可以使用Devel::Peek模块作弊来查看内部(非物理)内存地址:

 use Devel::Peek;

 foreach ( 0 .. 5 ) {
      my $var = $_;
      Dump( $var );
      }

在这个小案例中,地址最终是相同的。这并不能保证在不同的情况下,甚至是相同的程序,它总是一样的:

SV = IV(0x9ca968) at 0x9ca96c
  REFCNT = 1
  FLAGS = (PADMY,IOK,pIOK)
  IV = 0
SV = IV(0x9ca968) at 0x9ca96c
  REFCNT = 1
  FLAGS = (PADMY,IOK,pIOK)
  IV = 1
SV = IV(0x9ca968) at 0x9ca96c
  REFCNT = 1
  FLAGS = (PADMY,IOK,pIOK)
  IV = 2
SV = IV(0x9ca968) at 0x9ca96c
  REFCNT = 1
  FLAGS = (PADMY,IOK,pIOK)
  IV = 3
SV = IV(0x9ca968) at 0x9ca96c
  REFCNT = 1
  FLAGS = (PADMY,IOK,pIOK)
  IV = 4
SV = IV(0x9ca968) at 0x9ca96c
  REFCNT = 1
  FLAGS = (PADMY,IOK,pIOK)
  IV = 5

答案 3 :(得分:2)

您可以使用Benchmark模块对两种用途之间的差异进行基准测试,该模块是为这些类型的微基准比较而制作的:

#!/usr/bin/perl

use strict;
use warnings;

use Benchmark qw( cmpthese );

sub outside {
    my $x;

    for my $y ( 1 .. 1_000_000 ) {
        $x = $y;
    }

    return;
}

sub inside {
    for my $y ( 1 .. 1_000_000 ) {
        my $x = $y;
    }

    return;
}

cmpthese -1 => {
    inside => \&inside,
    outside => \&outside,
};

我的Windows XP SP3笔记本电脑上的结果:

          Rate  inside outside
inside  4.44/s      --    -25%
outside 5.91/s     33%      --

可以预见,当循环体仅执行一次时,差异不太明显。

那就是说, 我不会在循环外声明$x,除非我需要在循环内部分配给循环内$x的内容。

答案 4 :(得分:1)

在for循环或任何其他块中使用“my”是完全安全的。通常,您不必担心perl中的内存泄漏,但在这种情况下使用非垃圾收集语言(如C ++),您将同样安全。普通变量在具有范围的块的末尾被释放。