2011-12-23 23 views
6

Sadece yaklaşık K & R okumayı bitirdikten ediyorum ve bütün bildiğim C'dir çökmesini. Tüm derlemem, MinGW kullanarak Windows komut satırından yapılır ve gelişmiş hata ayıklama yöntemleri hakkında bilgim yoktur (bu nedenle aşağıdaki 2. programımda "getto hata ayıklama" yorumu). anlama bellek ayırma, test programı

Ben beni daha iyi nasıl bellek ayırma çalıştığını anlamak yardımcı olacak birkaç küçük test programları yapmaya çalışıyorum. Bu ilk çift programlar malloc ya da ücretsiz kullanmazlar, sadece belleğin bir fonksiyona yerel diziler için nasıl tahsis edildiğini ve ayrıldığını görmek istedim. Benim düşüncem, anladıklarımla örtüşüp örtüşmediğini görmek için RAM kullanım sürecimi izliyorum. Aşağıdaki bu ilk program için beklediğim gibi çalışır. alloc_one_meg() işlevi 250.000 4 baytlık tamsayılar ayırır ve başlatır, ancak işlev döndükçe MB de ayrılır. Yani, bu fonksiyonu arka arkaya 1000000 kez çağırırsam, RAM kullanımımın 1MB'nin üzerinde olduğunu asla görmemeliyim. Ve çalışıyor. Aşağıda bu ikinci program için
#include <stdio.h> 
#include <stdlib.h> 

void alloc_one_meg() { 
    int megabyte[250000]; 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
} 

main() 
{ 
    int i; 
    for (i=0; i<1000000; i++) { 
     alloc_one_meg(); 
    } 
} 

, fikri ben özyineleme ile gerçekleştirilebilir ki aynı anda, aynı işlevi çalışan 1000 kopyası olması, fonksiyon çıkmasına izin verilmez oldu. Benim teorim, programın tamamlandıktan sonra programın ayrılmasından önce 1GB RAM harcayacaktı. Ancak, özyineleme yoluyla 2. döngüyü geçmez (getto hata ayıklama yorum bölümüne bakın). Program oldukça bilgilendirici olmayan (benim için) ileti ile çöküyor (bir Windows pop-up söyleyerek ____. Exe bir sorunla karşılaştı). Genelde getto hata ayıklama yöntemiyle her zaman her şeyin altını çizebilirim ... ama burada çalışmıyor. Şoktayım. Bu kodla ilgili sorun nedir? Teşekkürler!

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

int j=0; 

void alloc_one_meg() { 
    int megabyte[250000]; 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
    j++; 
    printf("Loop %d\n", j); // ghetto debug 
    if (j<1000) { 
     alloc_one_meg(); 
    } 
} 

main() 
{ 
    alloc_one_meg(); 
} 

Takip soru here yayınlanmıştır.

+2

Ve şimdi bir yığın taşması kazasında var, daha iyi bir bellek anlaması var. Komik şeyler böyle nasıl çalışır. –

+2

Yup, programlama konusunda yeniyim, ama test fikrine yeni değil. Ben bir mühendisim ve ağır bir yazılımcıyım, KULLANICI, ve çok iyi bildiğim şeyleri anlamanın en iyi yolu! :-) – The111

cevap

3

Bir yığın taşması içine koşuyoruz.

Yerel otomatik depolama değişkenleri (örneğin megabyte gibi) alan miktarını sınırlı yığını üzerine dağıtılır. malloc, daha büyük tahsislere izin veren yığına tahsis eder.

Burada daha fazla bilgi edinebilirsiniz:

http://en.wikipedia.org/wiki/Stack_overflow

(C dili bellek tahsis edilir nerede belirtmez unutmamalıdır - yığını ve yığın uygulama detaylar)

+4

Ne kadar havalı, stackoverflow.com adresindeki yığın taşması hakkında bilgi aldım. Bunu meta üzerine yazmalıyım! Açıklama ve bağlantı için teşekkürler. – The111

+0

malloc() alanı daha büyük alana sahip değil - "yığın" için ayrılan çöp miktarını ve miktarını görün. –

2

büyüklüğü Bir Windows programında yığın genellikle 1 MB civarındadır, bu nedenle ikinci tekrarda, yığının taşmasını sağlarsınız.

void alloc_one_meg() { 
    int *megabyte = malloc(sizeof(int) * 250000); // allocate space for 250000 
                // ints on the heap 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
    j++; 
    printf("Loop %d\n", j); // ghetto debug 
    if (j<1000) { 
     alloc_one_meg(); 
    } 

    free(megabyte); // DO NOT FORGET THIS 
} 

söyledi: Sen yığını üzerinde böyle büyük diziler tahsis edilmemelidir, tahsis ve Öbek bellek ayırması malloc ve free kullanmak (Dizilerin böyle boyutları için çevrede malloc almak için bir yolu yoktur) Aslında, bir programın yığın boyutunu değiştirebilir ve daha büyük yapabilir (üretim kodu olarak değil, sadece eğitimsel bir alıştırma olarak yapsam bile). Visual Studio için use the /F compiler option'u ve linux üzerinde setrlimit(3)'u kullanabilirsiniz. Yine de MinGW ile ne kullanacağımı bilemiyorum.

+0

Malloc/free kullanmak istemediğini söyledi. – Pubby

+2

@Pubby bunları kullanamıyor –

+0

Bu test serisinin büyük bir kısmının bir kısmı malloc'un amacını ve özgürlüğünü anlamama yardımcı olmaktı. Önce onlar olmadan birkaç test yapmak istedim, onlarla birkaç test yaptım. Yığın değişkenlerinin malloc/free ile ilgili yaşamı olurken, yerel yığın değişkenlerinin işleve giriş/çıkışla ilgili yaşamı olduğunu biliyordum, ancak yığının böyle küçük bir sınırının olduğunu fark etmemiştim. Bu yüzden bu testle çok şey öğrendim. :-) – The111

0

StackOverflow. Bu bir hile sorusu mu?

+0

Hayır, sadece bir noob'um. Çok hızlı bir şekilde öğreniyorum ki, K & R'dan (şu ana kadar benim tek bilgi kaynağım dediğim gibi) elde edemediğimi bilmem gereken C hakkında çok şey var.Böyle bir soru sormamı engelleyecek bilgi hakkında bilgi edinmek için iyi bir yer neresidir? Yığın/yığın, bu tür bir şey (bu kavramlar K & R'da mevcut değil ve neden olduğunu anlıyorum). – The111

1

özyinelemeli fonksiyonel çağrıları aracılığıyla tahsis bellek yığınından ayrılır. Tüm yığın hafızası bitişik olmalıdır.İşleminiz bir iş parçacığı başlattığında, Windows bu iş parçacığı yığını için bir dizi sanal bellek alanı ayıracaktır. Ayrılacak bellek miktarı, EXE dosyanızın "PE üstbilgisinde" belirtilir. PE "Taşınabilir Yürütülebilir" anlamına gelir.

 100000 size of stack reserve 
     2000 size of stack commit 

:

dumpbin /headers dumpbin.exe

... sonra bazı çıkışı ve vardır: dumpbin programını kullanarak

girdi dosyası olarak kendisi (dumpbin.exe) ile, Visual Studio ile birlikte gelen "100000", 1.048.576'ya eşit bir onaltılık sayısıdır, yani bu yaklaşık 1 MB'ı temsil eder. Başka bir deyişle, işletim sistemi yığın için yalnızca 1 MB'lık bir adres aralığı ayırır. Bu adres aralığı kullanıldığında, Windows yığınının arttırılması için daha fazla ardışık bellek aralığı ayırabilir veya olmayabilir. Sonuç, daha fazla bitişik adres aralığının mevcut olup olmamasına bağlıdır. İş parçacığı başladığında yapılan diğer tahsisatlar nedeniyle, mevcut olması pek olası değildir.

Windows altında maksimum miktarda sanal bellek ayırmak için VirtualAlloc işlev ailesini kullanın.

İlgili konular