2012-07-23 85 views
1

進程的虛擬地址空間從進程的text,databss段開始。在這個堆分配被放置之後,堆向着更大的內存地址增長。但是,在使用堆的一部分之前,必須分配內存塊(valloc等),否則發生(或應該發生)。爲什麼不預先分配內存就可以使用堆棧?

堆棧從虛擬地址空間中的初始大地址向較小值增長。據我所知,這個工作沒有虛擬內存分配。在堆不可用的情況下如何在沒有事先分配內存的情況下使用堆棧? (它的線性虛擬地址空間是相同的)。

據我所知alloca就是sub esp, <size>。但是堆棧正在使用的虛擬地址空間區域必須在此之前以某種方式分配,對吧?

回答

1

確實段故障,以某種方式。這是一種「懶惰」的優化。操作系統會盡可能多地作弊,只要這種差異不是外部可觀察的。

但是,與正常的段錯誤一樣,陷阱不會導致生成信號(默認情況下會殺死進程)。而是,操作系統驗證是否超出了允許的線程大小,然後從零池中提取新頁面。

在Windows下,該機制被命名爲「守護頁」,我不知道在Linux下有一個類似的命名。無論哪種方式,一個警衛頁在技術上只不過是一個寫保護的頁面(或一個不存在的頁面),它被操作系統記憶爲「特殊」,所以當觸摸時可能會發生某些特定操作。

這與動態分配(malloc,也就是sbrk)的工作原理非常相似。分配內存時,只要不訪問分配的內存,就不會發生太多事情。唯一發生的事情是操作系統「記得」你增長了數據段。
如果現在發生故障,操作系統將創建頁面,或分別從零池中取出它,並假裝它一直在那裏。你永遠不知道它之前沒有。

+0

好的,這解釋了它。很好的回答! – ritter 2012-07-23 15:07:28

+0

Linux不使用警衛頁面。錯誤處理程序只是通過算術檢查錯誤地址位於可以從當前堆棧指針到達的區域,即:地址+65536 + 32 * sizeof(無符號長整型)< regs-> sp',它允許輸入$ 65535,$ 31 '去工作。參見'arch/x86/mm/fault.c:do_page_fault()'。 – ninjalj 2012-07-23 17:40:36