2010-01-25 31 views
6

Một Perl thành ngữ để loại bỏ giá trị nhân bản từ một mảng:Không sử dụng undef như giá trị băm lưu bất kỳ bộ nhớ trong Perl?

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

Là nó rẻ hơn để sử dụng phiên bản này:

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

Tôi đã thử nghiệm nó với những một lớp lót, và dường như đó là sự thật trên một số phiên bản của 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

Bạn có gặp phải sự cố về bộ nhớ hoặc bạn chỉ tò mò không? –

+0

Tò mò. Như tôi thấy, sự thay đổi khó có thể tiết kiệm đáng kể số lượng ram. –

Trả lời

8

Vâng, undef được coi là giá trị trọng lượng, có nghĩa là tất cả các tham chiếu đến điểm này anh ta cùng datum. Bạn không nhận được điều đó cho các chữ khác. Tuy nhiên, bạn vẫn cần chi phí của vùng tham chiếu. Tuy nhiên, tôi không thấy nó lưu bất kỳ bộ nhớ nào cho tôi trên Perl 5.10 hoặc 5.11 trên Mac OS X. Trong khi perl có thể không sử dụng nhiều bộ nhớ hơn trong trường hợp undef, tôi đặt cược nó dự đoán sẽ sử dụng nhiều bộ nhớ hơn. Tuy nhiên, tôi không quan tâm đến việc điều tra sử dụng bộ nhớ trong internals ngay bây giờ.

Devel::Peek là khá tiện dụng cho thấy những thứ như thế:

#!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); 

Kết quả trông hơi đáng sợ lúc đầu, nhưng bạn thấy rằng undef giá trị là NULL(0x0) thay vì giá trị chuỗi cá nhân (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 cũng cho tôi kết quả giống hệt nhau. Có lẽ perl bắt đầu cache ints nhỏ, như python? :-) –

+0

Tôi đã thử nó với cùng giá trị và các giá trị khác nhau cho mỗi khóa và có cùng kết quả. Tôi nghĩ rằng Perl có lẽ đang lấy một phần lớn bộ nhớ với dự đoán làm đầy nó với các giá trị sau này. –

+1

5.10 trở lên là tốt hơn nhiều khi sử dụng bộ nhớ tối thiểu cho những thứ chỉ là một int hoặc chỉ là một tham chiếu. Trước đây, một sv có hai phần, một phần có refcnt, flags, và một con trỏ đến phần còn lại; chỉ có một undef sẽ kết thúc không có phần thứ hai. Bây giờ cấu trúc ban đầu có một trường bổ sung được sử dụng để được lưu trữ trong cấu trúc thứ hai (trường nào nó phụ thuộc vào kiểu). – ysth

Các vấn đề liên quan