2012-04-30 103 views
1

所以我寫了一個玩具C程序,將故意導致堆棧溢出,正好與我的系統的限制周圍玩:爲什麼這個堆棧溢出這麼快?

#include <stdio.h> 

int kefladhen(int i) { 
    int j = i + 1; 
    printf("j is %d\n",j); 
    kefladhen(j); 
} 

int main() { 
    printf("Hello!:D\n"); 
    kefladhen(0); 
} 

我很驚訝地發現,分段錯誤之前打印的最後一行是「j是174651」。當然,每次運行它的確切數量都會有所變化,但總的來說,我驚訝地發現,17.4萬個堆棧幀足以耗盡我的4GB linux筆記本電腦上的進程的內存。我認爲printf可能會產生一些開銷,但是在遞歸調用kefladhen()之前printf會返回,所以堆棧指針應該回到之前的位置。我每次調用只存儲一個int,所以每個堆棧幀總共只有8個字節,對嗎?因此,其中有一萬七千多個實際使用的內存只有大約一兆字節和一半,這對我來說似乎很低。我在這裏誤解了什麼?

+0

您的默認堆棧大小有多大?它通常介於1MB和2MB之間... –

+1

請注意,堆棧不僅存儲本地變量。例如,返回地址。 – delnan

+1

在bash提示符處嘗試'ulimit -a'(或'ulimit -s'來獲取堆棧大小)。你也可以用'sizeof(int)'來驗證你的整數的大小。 – pmg

回答

8

......但總的來說,我很驚訝,174千奇堆棧幀都足以耗盡了我的4GB的Linux筆記本電腦進程的內存...

注意,堆棧不是一般的內存池。堆棧是爲提供堆棧而預先分配的塊。它可能只是機器上4GB內存中的1MB。我的猜測是你的堆棧大小約爲1.3MB;對於174,651個八字節幀(返回地址爲4個字節,對於int爲4個字節)就足夠了。

1

其他人已經討論過堆棧的大小和分配。 「每次運行它的確切數量會有所變化」的原因與多線程系統上的高速緩存性能有關。

通常,您可以預期爲堆棧預先分配的內存是頁面對齊的。但是,起始堆棧指針會因線程/線程/進程/進程/任務到任務而異。這有助於避免緩存行刷新,失效和加載。如果所有任務/線程/進程都有相同的虛擬地址作爲堆棧指針,那麼只要發生上下文切換,就會有更多的緩存衝突。爲了減少這種可能性,許多操作系統將在起始堆棧頁面的某處存在起始堆棧指針,但不一定位於頂部或同一位置。因此,當發生上下文切換和隨後的堆訪問時,有...

  1. 一個更好的機會的變量將已經在緩存
  2. 一個更好的機會,不會有緩存碰撞

希望這會有所幫助。

相關問題