धागा ढेर आधार पते प्राप्त करें: wj32 showed के रूप में, धागा जानकारी ब्लॉक के StackBase
का उपयोग करें।
थ्रेड स्टैक आकार प्राप्त करें: आरक्षित आरक्षित आकार (जो कि यह अधिकतम आकार है) निर्धारित करें। StackLimit
शो lowest commited address है, जो दिखा सकता है कि ढेर कितनी बड़ी हो गई है, इसकी सीमा नहीं है। यह भी नहीं कि CreateThread
पर जाने वाले स्टैक आकार प्रारंभिक प्रतिबद्ध आकार है, आरक्षित आकार नहीं जब तक आप STACK_SIZE_PARAM_IS_A_RESERVATION
ध्वज पास नहीं करते। आपके प्रोग्राम का स्टैक आकार linker parameter द्वारा निर्दिष्ट किया गया है और यदि आप निर्दिष्ट नहीं करते हैं तो 1 एमबी तक डिफ़ॉल्ट है। तो सबसे अधिक संभावना है कि सभी धागे में 1 एमबी स्टैक आरक्षण हो।
के अंतिम पृष्ठ के बाद से stack is a guard page आप क़यास StackPage
से शुरू करते हैं और प्रत्येक में कम ढेर पेज VirtualQuery
जाँच गार्ड पेज कि ढेर के अंत होगा खोजने के लिए कर सकते हैं। यह निश्चित रूप से कार्यान्वयन परिभाषित व्यवहार पर निर्भर है।
वर्तमान ढेर सूचक प्राप्त करें: आप StackLimit
का उपयोग अपने ढेर की अधिकतम प्रतिबद्ध आकार पाने के लिए कर सकता है, लेकिन यह है कि वर्तमान सूचक के रूप में ही नहीं है। esp
स्पष्ट रूप से वर्तमान स्टैक स्थिति है और StackLimit
से अधिक हो सकता है।
आरक्षित बनाम पर नोट। आरक्षित आरक्षित में इसका मतलब है कि आभासी पते को उपयोग के लिए आरक्षित किया गया है और किसी और चीज के लिए नहीं लिया जा सकता है। आरक्षित पते किसी भौतिक या वर्चुअल मेमोरी का उपभोग नहीं करते हैं। एक बार यह काम करने के बाद यह पता भौतिक या आभासी स्मृति में मैप किया जाएगा और इसका उपयोग किया जा सकता है। विंडोज उपयोगकर्ता थ्रेड्स में एक निश्चित स्टैक रिजर्व आकार होता है - पता स्थान स्टैक के लिए आरक्षित है और इसे बढ़ाया नहीं जा सकता है और एक परिवर्तनीय प्रतिबद्ध आकार - स्टैक केवल इसकी आवश्यकता होती है (प्रतिबद्ध) स्मृति की आवश्यकता होती है।
संपादित
गार्ड पेज से काम नहीं चलेगा जाँच पर मेरे विचार। मैंने एक परीक्षण कार्यक्रम लिखा और गार्ड पेज प्रतिबद्ध सीमा पर सेट है, इसलिए यह काम नहीं करता है। लेकिन मुझे लगता है कि स्टैक पर कहीं भी VirtualQuery
चलाना स्टैक पर सबसे कम पते के AllocationBase
देगा, क्योंकि रिजर्व आकार एक बार आवंटित किया गया था। निम्न उदाहरण कार्रवाई में यह पता चलता है:
#include <windows.h>
#include <WinNT.h>
#include <stdio.h>
DWORD GetThreadStackSize()
{
SYSTEM_INFO systemInfo = {0};
GetSystemInfo(&systemInfo);
NT_TIB *tib = (NT_TIB*)NtCurrentTeb();
DWORD_PTR stackBase = (DWORD_PTR)tib->StackBase;
MEMORY_BASIC_INFORMATION mbi = {0};
if (VirtualQuery((LPCVOID)(stackBase - systemInfo.dwPageSize), &mbi, sizeof(MEMORY_BASIC_INFORMATION)) != 0)
{
DWORD_PTR allocationStart = (DWORD_PTR)mbi.AllocationBase;
return stackBase - allocationStart;
}
return 0;
}
DWORD WINAPI ThreadRtn(LPVOID param)
{
DWORD stackSize = GetThreadStackSize();
printf("%d\n", stackSize);
return 0;
}
int main()
{
ThreadRtn(NULL);
HANDLE thread1 = CreateThread(NULL, 65535, ThreadRtn, NULL, 0, NULL);
WaitForSingleObject(thread1, -1);
HANDLE thread2 = CreateThread(NULL, 65535, ThreadRtn, NULL, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
WaitForSingleObject(thread2, -1);
return 0;
}
यह आउटपुट:
के रूप में यह होना चाहिए।
ध्यान दें कि [इटेनियम में * दो स्टैक *] हैं (http://blogs.msdn.com/b/oldnewthing/archive/2005/04/21/410397.aspx)। अब तक, हर कोई केवल स्थानीय परिवर्तनीय ढेर पर देख रहा है, लेकिन रजिस्टर स्टैक भी है (जहां अन्य चीजों के साथ वापसी पते जाते हैं)। तो यह तकनीक स्टैक ओवरफ़्लो को रोकने के लिए पर्याप्त नहीं है क्योंकि आप केवल एक ढेर की जांच कर रहे हैं। –
दिलचस्प ... लेकिन अगर यह "रजिस्टर स्टैक" वास्तव में * हार्डवेयर * आश्रित है, तो इंटेल या जो भी लागू होता है, उसे स्थानीय चर आवंटन के लिए नियमित कॉल स्टैक का उपयोग नहीं करना चाहिए यदि रजिस्टर स्टैक भरा हुआ हो; आखिरकार, स्थानीय चरों को स्टोर करने के लिए रजिस्टरों का उपयोग करना जरूरी नहीं है, है ना? – Jong
कोई कानून नहीं है जो कहता है कि सभी प्रोसेसर x86 की तरह होना चाहिए। (और Itanium रजिस्टर रजिस्टर विंडो के साथ शायद ही एकमात्र प्रोसेसर है।) –