2010-01-25 3 views
6

Perl-идиомы для удаления повторяющихся значений из массива:Использует undef как значения хэша, сохраняя любую память в Perl?

@uniq = keys %{{map{$_=>1}@list}} 

ли дешевле использовать эту версию:

@uniq = keys %{{map{$_=>undef}@list}} 

я тестировал его с этими остротами, и кажется, что это правда в некоторых версиях Perl:

perl -e 'my %x; $x{$_} = 1 for 0..1000_000; system "ps -ovsz $$"' 
perl -e 'my %x; $x{$_} = undef for 0..1000_000; system "ps -ovsz $$"' 
+0

У вас проблемы с памятью или вам просто интересно? –

+0

Любопытный. Как я вижу, изменение вряд ли может сэкономить заметное количество барана. –

ответ

8

Ну, undef должно быть значение мухи, а это означает, что все ссылки на него указывают на т он такой же. Вы не понимаете этого для других литералов. Вам все еще нужны накладные расходы на слот, который ссылается на него. Тем не менее, я не вижу, чтобы это сохраняло память для меня на Perl 5.10 или 5.11 в Mac OS X. Хотя perl может не использовать больше памяти в корпусе undef, я уверен, он ожидает использования большего объема памяти, чтобы он все равно ее хватал. Тем не менее, я не заинтересован сейчас в изучении использования памяти во внутренних деталях.

Devel::Peek очень удобно для показа такого рода вещи:

#!perl 

use Devel::Peek; 

my $a = undef; 
my $b = undef; 

Dump($a); 
Dump($b); 


my %hash = map { $_, undef } 1 .. 3; 
$hash{4} = 'Hello'; 
Dump(\%hash); 

Выходной сигнал выглядит немного страшно сначала, но вы видите, что undef значения NULL(0x0) вместо отдельных значений строк (PV):

SV = NULL(0x0) at 0x100208708 
    REFCNT = 1 
    FLAGS = (PADMY) 
SV = NULL(0x0) at 0x100208738 
    REFCNT = 1 
    FLAGS = (PADMY) 
SV = RV(0x100805018) at 0x100805008 
    REFCNT = 1 
    FLAGS = (TEMP,ROK) 
    RV = 0x100208780 
    SV = PVHV(0x100809ed8) at 0x100208780 
    REFCNT = 2 
    FLAGS = (PADMY,SHAREKEYS) 
    ARRAY = 0x100202200 (0:5, 1:2, 2:1) 
    hash quality = 91.7% 
    KEYS = 4 
    FILL = 3 
    MAX = 7 
    RITER = -1 
    EITER = 0x0 
    Elt "4" HASH = 0xb803eff9 
    SV = PV(0x100801c78) at 0x100804ed0 
     REFCNT = 1 
     FLAGS = (POK,pPOK) 
     PV = 0x100202a30 "Hello"\0 
     CUR = 5 
     LEN = 8 
    Elt "1" HASH = 0x806b80c9 
    SV = NULL(0x0) at 0x100820db0 
     REFCNT = 1 
     FLAGS =() 
    Elt "3" HASH = 0xa400c7f3 
    SV = NULL(0x0) at 0x100820df8 
     REFCNT = 1 
     FLAGS =() 
+0

5.10 дает мне одинаковые результаты. Может быть, perl начал кэшировать небольшие ints, например python? :-) –

+0

Я пробовал его с одинаковым значением и разными значениями для каждой клавиши и получал те же результаты. Я думаю, что Perl, вероятно, захватывает большой кусок памяти в ожидании заполнения его значениями позже. –

+1

5.10 и выше намного лучше используют минимальную память для вещей, которые являются просто int или просто ссылкой. Раньше у sv было две части, одна из которых имела refcnt, flags и указатель на остальные; только undef закончил бы без второй части. Теперь исходная структура имеет дополнительное поле, которое ранее было сохранено во второй структуре (какое поле зависит от типа). – ysth

Смежные вопросы