«Моя» перезаписывает память при вызове в цикле? - PullRequest
2 голосов
/ 31 августа 2009

Простой, но актуальный вопрос: перезаписывает ли «моя» память при вызове в цикле?
Например, «лучше» (с точки зрения утечек памяти, производительности, скорости) объявить это вне цикла:

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

Или я должен объявить это внутри цикла:

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

(я только что создал этот код, он не предназначен для того, чтобы что-либо делать или использоваться - как есть - в реальной жизни) Будет ли Perl выделять новое пространство в памяти для каждой из для итераций?

Ответы [ 5 ]

9 голосов
/ 31 августа 2009

Амир уже сказал вам, что произойдет.

Я рекомендую придерживаться второй версии, если нет причин использовать первую. Вы не хотите заботиться о предыдущем состоянии $variable. Проще всего начинать каждую итерацию с новой переменной. И если переменная содержит ссылку, вы можете на самом деле выстрелить себе в ногу , если вы вставите ее в массив.

Edit:

Да, производительность снижается. Использование переработанной переменной будет быстрее. Однако трудно представить, насколько быстрее это будет, поскольку это будет зависеть от вашей конкретной ситуации. Независимо от того, насколько это быстрее, всегда помните: Преждевременная оптимизация - корень всего зла .

3 голосов
/ 01 сентября 2009

Это вещи, о которых вы не должны думать с динамическим языком, таким как 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 голосов
/ 31 августа 2009

Из приведенных выше примеров:

  1. Новое место для переменной не будет выделяться каждый раз, будет использоваться предыдущий.

  2. Новое пространство будет выделено для каждой итерации цикла и будет также отменено в той же итерации.

2 голосов
/ 02 сентября 2009

Вы можете сравнить разницу между двумя вариантами использования с помощью модуля 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 внутри цикла.

1 голос
/ 31 августа 2009

Вы в полной безопасности, используя «my» внутри цикла for или любого другого блока. В общем, вам не нужно беспокоиться об утечках памяти в perl, но вы были бы в такой же безопасности в таком случае с языком без сбора мусора, таким как C ++. Нормальная переменная освобождается в конце блока, в котором она имеет область видимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...