我正在編寫一個使用x86指令集的程序。當我使用存儲在大小爲40kb的堆棧中的本地數組時,它爲什麼會崩潰。使用帶有i5處理器的Windows7操作系統,在Visual C++編譯++速成版2008堆棧大小的最大使用限制是否有限制?
回答
我想你擊中的保護頁的形式捕捉
IM。爲了不浪費實際內存直到實際使用,Windows最初保留了完整的堆棧空間(默認爲1MB;可以通過編輯PE頭文件來更改),但是隻提交兩頁,並且使第二個頁面成爲警戒頁面。保護頁面是一個頁面(4KB)的內存,它在對其進行訪問時會觸發一個特殊的異常(STATUS_GUARD_PAGE_VIOLATION)。當內核檢測到一個保護頁面異常時,它會提交所觸及的頁面並在其後面添加另一個保護頁面。這樣,如果你的函數在堆棧中推送小變量,它會「自行」增長。
然而,有一個問題,如果你嘗試分配一個本地變量,它是在4K(4096個字節)的大小。通常情況下,堆棧分配是通過簡單地從ESP中減去完成的。如果您從中減去超過4K,然後嘗試寫入堆棧,則有可能會在防護頁上進行拍攝,並在其後訪問保留的內存。這個不會被內核捕獲,但會傳遞給你的程序,並且通常會導致崩潰。
的解決方案是簡單的 - 做堆疊在4K的塊分配(= 4096 = 0×1000字節)和接觸紙堆每一個後觸發保護頁。 MSVC編譯器通過在使用超過4K局部變量的函數開始時調用__chkstk()
函數自動執行此操作。這裏的功能從CRT源列表:
;***
;_chkstk - check stack upon procedure entry
;
;Purpose:
; Provide stack checking on procedure entry. Method is to simply probe
; each page of memory required for the stack in descending order. This
; causes the necessary pages of memory to be allocated via the guard
; page scheme, if possible. In the event of failure, the OS raises the
; _XCPT_UNABLE_TO_GROW_STACK exception.
;
; NOTE: Currently, the (EAX < _PAGESIZE_) code path falls through
; to the "lastpage" label of the (EAX >= _PAGESIZE_) code path. This
; is small; a minor speed optimization would be to special case
; this up top. This would avoid the painful save/restore of
; ecx and would shorten the code path by 4-6 instructions.
;
;Entry:
; EAX = size of local frame
;
;Exit:
; ESP = new stackframe, if successful
;
;Uses:
; EAX
;
;Exceptions:
; _XCPT_GUARD_PAGE_VIOLATION - May be raised on a page probe. NEVER TRAP
; THIS!!!! It is used by the OS to grow the
; stack on demand.
; _XCPT_UNABLE_TO_GROW_STACK - The stack cannot be grown. More precisely,
; the attempt by the OS memory manager to
; allocate another guard page in response
; to a _XCPT_GUARD_PAGE_VIOLATION has
; failed.
;
;*******************************************************************************
public _alloca_probe
_chkstk proc
_alloca_probe = _chkstk
push ecx
; Calculate new TOS.
lea ecx, [esp] + 8 - 4 ; TOS before entering function + size for ret value
sub ecx, eax ; new TOS
; Handle allocation size that results in wraparound.
; Wraparound will result in StackOverflow exception.
sbb eax, eax ; 0 if CF==0, ~0 if CF==1
not eax ; ~0 if TOS did not wrapped around, 0 otherwise
and ecx, eax ; set to 0 if wraparound
mov eax, esp ; current TOS
and eax, not (_PAGESIZE_ - 1) ; Round down to current page boundary
cs10:
cmp ecx, eax ; Is new TOS
jb short cs20 ; in probed page?
mov eax, ecx ; yes.
pop ecx
xchg esp, eax ; update esp
mov eax, dword ptr [eax] ; get return address
mov dword ptr [esp], eax ; and put it at new TOS
ret
; Find next lower page and probe
cs20:
sub eax, _PAGESIZE_ ; decrease by PAGESIZE
test dword ptr [eax],eax ; probe page.
jmp short cs10
_chkstk endp
在你的情況,你可能不需要這個複雜的邏輯,這樣的事情就可以了:
xor eax, eax
mov ecx, 40 ; alloc 40 pages
l1:
sub esp, 1000h ; move esp one page
mov [esp], eax ; touch the guard page
loop l1 ; keep looping
sub esp, xxxh ; alloc the remaining variables
有關堆棧的詳細信息,請參閱here和看守頁面。
@ igor-skochinsky-謝謝。有效 – user2004149 2013-03-11 11:41:31
- 1. 爲什麼堆棧大小有限制?
- 2. Linux中進程的堆棧大小是否有限制
- 3. stl堆棧對象的大小限制
- 4. GMAKE更改堆棧大小限制
- 5. VS2005:限制堆大小
- 6. Windows Phone堆大小限制
- 7. Java堆大小硬限制
- 8. chrome.hid.send的ArrayBuffer大小是否有限制?
- 9. 是否有.csv文件的最大文件大小硬限制?
- 10. java堆設置中的最大堆大小的限制
- 11. document.execCommand('copy')是否有大小限制?
- 12. Ruby對象是否有大小限制?
- 13. std :: unique是否有大小限制?
- 14. CGBitmapContextCreate()是否有大小限制?
- 15. 是否有ajax郵寄大小限制?
- 16. HTML5 Manifest是否有大小限制?
- 17. WritePrivateProfileStruct是否有大小限制?
- 18. Numpy:是否有數組大小限制?
- 19. MSMQ隊列大小是否有限制?
- 20. MBTiles文件是否有大小限制?
- 21. 霍夫曼壓縮文件大小是否有最大限制?
- 22. LDAP限制大小限制
- 23. 具有最大限制的堆棧對象
- 24. iPhone的輔助線程堆棧大小是否有上限?
- 25. 限制行的大小是否有利於MySQL表大小?
- 26. Node.js中的響應大小是否有大小限制
- 27. np.fromfile文件大小的最大限制?
- 28. 鉻中的Indexeddb最大大小限制
- 29. 最大調用堆棧大小超出 - 無限循環
- 30. PL SQL觸發器的大小限制是否限制爲32Kb?
那麼對堆棧一個本地陣列是不是一個漂亮的事情,如果你想成爲一個男人店呢其他地方,二來您的問題提供一些額外的信息(平臺最重要的)和三個沒有默認的限制,但有是幾種技術來確定你有多少內存。 – Pyjong 2013-03-11 10:05:10
IIRC大多數VC版本默認使用2MB堆棧大小。 – 2013-03-11 10:13:03