2013-05-28 36 views
8

nihayet son sayfayı boşaltır, ardından 99.999 sayfaları boşaltır, 100.000 4KB'dir boyutlu sayfaları oluşturur aşağıdaki C kodu, düşünün ve:Bellek sızıntısı

#include <stdio.h> 
#include <stdlib.h> 

#define NUM_PAGES 100000 

int main() { 
    void *pages[NUM_PAGES]; 

    int i; 
    for(i=0; i<NUM_PAGES; i++) { 
     pages[i] = malloc(4096); 
    } 

    printf("%d pages allocated.\n", NUM_PAGES); 
    getchar(); 

    for(i=0; i<NUM_PAGES-1; i++) { 
     free(pages[i]); 
    } 

    printf("%d pages freed.\n", NUM_PAGES-1); 
    getchar(); 

    free(pages[NUM_PAGES-1]); 

    printf("Last page freed.\n"); 
    getchar(); 

    return 0; 
} 

bunu derlemek, çalıştırmak İşlemin bellek kullanımını izler, bellek kullanımının ilk getchar'dan (bellek 100.000 sayfa için ayrıldığında) yaklaşık 400MB'a ulaştığını görebilirsiniz, sonra 99.999 sayfa ayrıldıktan sonra bile aynı kalır (saniye sonra) getchar) ve son sayfa ayrıldığında son olarak 1MB'a düşüyor.

Yani, sorum bu neden oluyor? Tüm sayfalar sadece tüm sayfalar serbest bırakıldığında neden işletim sistemine döndürülür? Bu tür bir şeyin gerçekleşmesini engelleyen sayfa boyutu veya herhangi bir sayfa hizalaması var mı? Demek istediğim, herhangi bir sayfa boyutu veya hizalama var mıdır, sadece bir sayfa boşaldığında kötü bir sayfanın tümüyle işletim sistemine döndürülmesini sağlar mı?

+3

Bu, ayırmaların çok küçük olmasından dolayı, C kitaplığınız, başlatılmamış verilerini dinamik olarak yeniden boyutlandırmak için sbrk() işlevini kullanır. Sıralıdır, bu yüzden sadece en son tahsisat boşaldığında büzülür. Atama boyutunu 131072 bayt (128k) olarak artırırsanız, strace, bunun yerine tahsisler için 'mmap()' kullandığını gösterir ve her bir 'free()' aslında OS'ye ayırmayı döndürür. Bu nedenle, bir ayırma önbelleği kullanın ve yalnızca büyük parçaları OS'ye isteyin/döndürün. –

+0

@NominalAnimal Adam, hayatımı kurtardın! Yukarıdaki ve aşağıdaki yorumlar için çok teşekkür ederim. Tam olarak cevaplardan beklediğim buydu. Eğer cevapladıysanız (yorumda bulunmadıysanız), cevabınızı kabul ederdim ... – LuisABOL

cevap

5

Bu, tamamen uygulamaya bağımlıdır, ancak bunun bellek ayırıcısının nasıl çalıştığıyla ilgili olduğuna inanıyorum. Tipik olarak, bellek yöneticisi işletim sisteminden daha fazla belleğe ihtiyaç duyduğunda, ek bellek istemek için sbrk işlevini çağırır. Bu işlevin tipik olarak uygulanması, OS'nin bir işaretçiyi işlemin uzaya gidebileceği bir sonraki boş adrese depolamasıdır. Bellek, yığın olarak, çağrı yığınının çalıştığı şekilde çoğalır. - 4, programın içindeki hafıza yöneticisi bu gibi serbest puanlayacağı

(existing memory) | Page 0 | Page 1 | Page 2 | Page 3 | Page 4 | (next free spot) 

Bu kurulumla, serbest sayfalar 0 ise: Örneğin, eğer bu gibi görünebilir, belleğin beş sayfa tahsis : Sayfa 4 kullanılıyor yapılana kadar

(existing memory) |         | Page 4 | (next free spot) 

OS yığın gibi moda bellek ayrılırken olduğundan, programdan tüm bu bellek geri olamaz.

(existing memory) |            (next free spot) 

Ve bu noktada programın bellek yöneticisi OS boş alan o büyük miktarda dönebilirsiniz: çok son sayfayı özgür sonra, işlemin bellek gibi görünecektir

(existing memory) | (next free spot) 

Diğer bir deyişle, bellek bir yığın olarak ayrıldığından, ayırdığınız en son şeyi serbest bırakana kadar, işletim sistemi herhangi bir belleği geri yükleyemez.

Bu yardımcı olur umarız!

+0

Tamam, cevap verdiğiniz için çok teşekkürler! Bellek ayırma hakkında çok iyi bir açıklama. Ancak, yığın-benzeri bellek tahsisinden kaçınmak için herhangi bir yol biliyor musunuz, yani tek tek ayrılan ayrı sayfaların tahsisini bilmek isterim. – LuisABOL

+2

@ LuisAntonioBotelhoO.Leite İşletim sisteminden doğrudan bellek almak/bırakmak için muhtemelen OS'ye bağlı çağrılara ihtiyacınız olacaktır. Pencerelerin altında, [VirtualAlloc] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887 (v ​​= vs.85) .aspx) ve [VirtualFree] (http: // msdn. microsoft.com/tr-tr/kütüphane/windows/masa/aa366892 (v = VS.85) .aspx). Ünitelerde, [sbrk (2)] kullanın (http://linux.die.net/man/2/sbrk). Sadece malloc/free kullanmak ve sbrk'ten kaçınmak için uyarıldığınızı unutmayın. – Anthony

+0

@ anthony-arnold Çok teşekkür ederim! – LuisABOL