2016-09-15 99 views
12

Ben boyutunda, bir büyüklük haline hatta bazen GBs metinsel verilerin dev bir yığın okur bir uygulama var. Bu skaler üzerinde substr kullanıyorum, verilerin çoğunu başka bir skalaya okumak ve ayıklanan veriyi boş bir dizeyle değiştirmek, çünkü artık ilk skalerde gerekmiyor. Yakın zamanda bulduğum şey, Perl'in ilk skalenin belleğini boşa çıkarmaması, mantıksal uzunluğunun değiştiğini kabul etmesiydi. Yani yapmam gereken şey, ilk skalerden gelen verileri bir üçüncü tekrar, undef ilk skaler ayıklamak ve ayıklanan verileri tekrar yerine koymaktır. Sadece bu şekilde, ilk skaler tarafından işgal edilen hafıza gerçekten serbest kalır. Bu scalar veya ayrılmış bellek bloğundan daha az başka bir değere undef atanması, ayrılan bellekle ilgili hiçbir şeyi değiştirmez.Perl: Kapsam dışı kalmaksızın serbest bırakılan skaler belleğin ne zaman boş olduğu?

 $$extFileBufferRef = substr($$contentRef, $offset, $length, ''); 
    $length   = length($$contentRef); 
    my $content   = substr($$contentRef, 0, $length); 
    $$contentRef  = undef($$contentRef) || $content; 

$$contentRef örneğin olabilir:

aşağıdaki

Şimdi ne yaptığım olduğunu İlk satırda 5 GB boyutunda, 4,9 GB veri alıp çıkarılan verileri değiştiriyorum. İkinci satır şimdi, ör. Dizenin uzunluğu olarak 100 MB veri, ancak ör. Devel::Size::total_size hala, bu skalar için 5 GB'lik verilerin tahsis edildiğini gösterir. Ve $$contentRef için undef veya atama bu konu hakkında bir şey değişmez görünmüyor, bunu sayısal alan üzerinde bir fonksiyonu olarak undef çağırmanız gerekir.

$$contentRef'un arkasındaki belleğin substr uygulandıktan sonra en azından kısmen serbest kalmasını beklerdim. değişkenler kapsam dışına giderseniz ... vaka olmak Yani, bellek sadece arındırılır

gelmiyor mu? Ve eğer öyleyse, neden aynı sayısal alan üzerinde bir fonksiyonu olarak undef çağrılmasına farklı undef atama nedir?

+3

Başka bir yerde bu belleğe ** mi ihtiyacınız var? – simbabque

+0

Evet, farklı nedenlerden dolayı verilerin çok sayıda kopyası var ve ek olarak tüm süreç paralel olarak yürütülebiliyor. Yani tüm süreç boyunca boşa harcanan GB bellekler umursamıyorum. Ve evet, kötü bir tasarım ve tüm olabilir, ama şu anda bu şekilde ... –

cevap

13

Sizin analiz doğrudur.

$ perl -MDevel::Peek -e' 
    my $x; $x .= "x" for 1..100; 
    Dump($x); 
    substr($x, 50, length($x), ""); 
    Dump($x); 
' 
SV = PV(0x24208e0) at 0x243d550 
    ... 
    CUR = 100  # length($x) == 100 
    LEN = 120  # 120 bytes are allocated for the string buffer. 

SV = PV(0x24208e0) at 0x243d550 
    ... 
    CUR = 50  # length($x) == 50 
    LEN = 120  # 120 bytes are allocated for the string buffer. 

Sadece Perl overallocate dizeleri yapar, yok mu bunun yerine onlara kapsamı girilir dahaki sefere yeniden, kapsam dışına çıkar hatta ücretsiz değişkenler.

Mantık, belleğe bir kez gereksinim duyduysanız, yeniden gereksinim duyacağınız büyük bir olasılık var. bir sayısal için undef atama Aynı nedenle

, onun dize tampon özgür değildir. Ancak Perl, eğer isterseniz, arabellekleri serbest bırakma şansı verir, böylece skaler'i undef'a aktarmanız, skaler iç tamponların serbest kalmasını zorlar.

$ perl -MDevel::Peek -e' 
    my $x = "abc"; $x .= "def"; Dump($x); 
    $x = undef;     Dump($x); 
    undef $x;     Dump($x); 
' 
SV = PV(0x37d1fb0) at 0x37eec98 # PV: Scalar may contain a string 
    REFCNT = 1 
    FLAGS = (POK,pPOK)    # POK: Scalar contains a string 
    PV = 0x37e8290 "abcdef"\0  # The string buffer 
    CUR = 6 
    LEN = 10      # Allocated size of the string buffer 

SV = PV(0x37d1fb0) at 0x37eec98 # PV: Scalar may contain a string 
    REFCNT = 1 
    FLAGS =()      # No "OK" flags: undef 
    PV = 0x37e8290 "abcdef"\0  # The string buffer is still allcoated 
    CUR = 6 
    LEN = 10      # Allocated size of the string buffer 

SV = PV(0x37d1fb0) at 0x37eec98 # PV: Scalar may contain a string 
    REFCNT = 1 
    FLAGS =()      # No "OK" flags: undef 
    PV = 0       # The string buffer has been freed. 
+0

Teşekkürler, bu kapsam-davranış bitti farkında değildi. OS işlemi veya Perl yorumlayıcısı başına bu önbelleğe alma yaklaşımı var mı? Çünkü mod_perl kullanıyorum ve istek üzerine büyük miktarlarda belleğin tutulduğunu fark ettim. Bir bellek düşüncesi bir yere sızdı, ama bu "akıllı" önbellekleme olabilir. Bir süreç hafızada birçok yorumcuya sahip olabilir ve eğer bazı veriler GB'yi önbelleğe alırsa sorunum olur. –

+0

Maalesef cevabınızı anlayamadığımı düşünün: İşlem başına birçok ileti dizisi, haklıysam mod_perl bir havuzda bulunan bellekte bulunan rasgele yorumlayıcıları seçer.Bu nedenle, önbelleğe alınmış/ayrılmış belleğin, tercümanlara atanması gerekir ve sadece, bu tür önbelleğe alınmış/ayrılmış belleğe sahip bazı yorumlayıcılar yürütürse mi kullanılır? Diğer tercümanlar fayda sağlamazlar, ancak kendilerini kendilerine ayırırlar. Tercüman bırakan bir konu hafızayı serbest bırakmaz. 10 tercüman, örneğin 10 * 2 GB veri tahsis edilmiştir. Sadece tercümanlar süreçten silindiğinde temizlenir. Sağ? –

+0

mod_perl-interpreters kullanımdan sonra serbest kalmazlar, bellekte kalırlar ve varsayılan olarak farklı threadler tarafından birçok kez kullanılırlar. Else mod_perl'in kendisi mantıklı olmaz çünkü tüm tercümanlar isteklerin hemen ardından serbest bırakılırsa herhangi bir performans elde edemezsiniz. Kodun tekrar tekrar derlenmesi gerekecek ... Belgeler aksi halde yazıyor: https://perl.apache.org/docs/2.0/user/config/config.html#Threads_Mode_Specific_Directives –