VirtualAlloc और HeapAlloc में क्या अंतर है?


82

वहाँ इस तरह के रूप Windows वातावरण में स्मृति को आबंटित करने विधि के बहुत सारे हैं VirtualAlloc, HeapAlloc, malloc, new

इस प्रकार, उनमें क्या अंतर है?

जवाबों:


83

प्रत्येक एपीआई विभिन्न उपयोगों के लिए है। हर एक को यह भी आवश्यक है कि जब आप मेमोरी के साथ काम कर रहे हों तो आप सही डीलक्लोलेशन / फ्रीजिंग फंक्शन का उपयोग करें।

VirtualAlloc

एक निम्न-स्तरीय, विंडोज एपीआई जो बहुत सारे विकल्प प्रदान करता है, लेकिन मुख्य रूप से काफी विशिष्ट स्थितियों में लोगों के लिए उपयोगी है। केवल मेमोरी को आवंटित कर सकते हैं (संपादित करें: 4KB नहीं) बड़ा हिस्सा। ऐसी परिस्थितियाँ हैं जहाँ आपको इसकी आवश्यकता होती है, लेकिन जब आप इन स्थितियों में से एक में होंगे तब आपको पता चल जाएगा। सबसे आम में से एक है यदि आपको किसी अन्य प्रक्रिया के साथ सीधे मेमोरी साझा करना है। सामान्य प्रयोजन स्मृति आवंटन के लिए इसका उपयोग न करें। VirtualFreeडीलकोलेट करने के लिए उपयोग करें ।

HeapAlloc

आप जो भी मेमोरी मांगते हैं, उससे बड़ी मात्रा में नहीं, आवंटित करता है VirtualAllocHeapAllocयह जानता है कि कॉल करने की आवश्यकता कब होती है VirtualAllocऔर आपके लिए यह स्वचालित रूप से होता है। जैसे malloc, लेकिन केवल Windows है, और कुछ और विकल्प प्रदान करता है। स्मृति के सामान्य भाग को आवंटित करने के लिए उपयुक्त है। कुछ विंडोज एपीआई की आवश्यकता हो सकती है कि आप इसका उपयोग उन मेमोरी को आवंटित करने के लिए करते हैं जो आप उनके पास जाते हैं, या अपने साथी HeapFreeको मुफ्त मेमोरी में उपयोग करते हैं जो वे आपके पास लौटते हैं।

malloc

स्मृति को आवंटित करने का सी तरीका। इसे प्राथमिकता दें यदि आप C ++ के बजाय C में लिख रहे हैं, और आप चाहते हैं कि आपका कोड उदा यूनिक्स कंप्यूटर पर भी काम करे, या कोई व्यक्ति विशेष रूप से कहता है कि आपको इसका उपयोग करने की आवश्यकता है। मेमोरी को इनिशियलाइज़ नहीं करता है। स्मृति के सामान्य विखंडू को आवंटित करने के लिए उपयुक्त है, जैसे HeapAlloc। एक साधारण एपीआई। freeडीलकोलेट करने के लिए उपयोग करें । विजुअल C ++ की mallocकॉल HeapAlloc

नया

मेमोरी आवंटित करने का C ++ तरीका। इसे प्राथमिकता दें यदि आप C ++ में लिख रहे हैं। यह किसी ऑब्जेक्ट या ऑब्जेक्ट को आवंटित मेमोरी में भी डालता है। deleteडीललॉकेट (या delete[]सरणियों के लिए) का उपयोग करें । विज़ुअल स्टूडियो के newकॉल HeapAlloc, और फिर ऑब्जेक्ट को इनिशियलाइज़ करते हैं, इस पर निर्भर करता है कि आप इसे कैसे कहते हैं।

हाल ही में सी ++ मानकों (सी ++ 11 और उससे अधिक) के लिए आपको मैन्युअल उपयोग करने के लिए है, तो delete, आप गलत कर रहे हैं और एक का उपयोग करना चाहिए स्मार्ट सूचक की तरह unique_ptrबजाय। C ++ 14 के बाद से, उसी के बारे में कहा जा सकता है new(जैसे कार्यों के साथ प्रतिस्थापित make_unique())।


कुछ अन्य समान कार्य भी हैं जैसे SysAllocStringकि आपको बताया जा सकता है कि आपको विशिष्ट परिस्थितियों में उपयोग करना है।


18
डौग: VirtualAlloc सख्ती से 4kb आवंटन तक सीमित नहीं है, यह GetSystemInfo (), SYSTEM_INFO :: dwAllocationGranularity द्वारा लौटाया गया आकार है। यह वास्तव में है शायद ही कभी 4KB। मेरे मेजबान पर, यह 64k है, मुझे आपके लिए उसी पर संदेह है। 4KB x86 ABI में विभिन्न डिस्क्रिप्टर तालिकाओं के लिए न्यूनतम पृष्ठ आकार प्रविष्टि है। 4KB सबसे छोटा आकार है जिसे अप्रत्यक्ष रूप से अनुमति दी जा सकती है, R / W / X, हालांकि यह VirtualAlloc के लिए किसी भी महत्व का नहीं है। यदि आप VirtualAlloc प्रलेखन को देखें, तो LARGE_PAGES विकल्प भी है (देखें msdn.microsoft.com/en-us/library/aa366568(VS.85).aspx )।
RandomNickName42

क्या आप जानते हैं कि DirectShow VirtualAlloc का उपयोग मैलोडोक का उपयोग करने के बजाय मीडिया के लिए मेमोरी बफ़र्स आवंटित करने के लिए क्यों करता है?
एविएड रोज़ेनखेय

Aviad: DirectShow मेमोरी को आरक्षित करने के लिए वर्चुअल एलोकेशन का उपयोग करता है ताकि यह प्रदर्शन अनुकूलन के लिए आवश्यक झंडे को पास कर सके, न कि ऐसी चीजें जिन्हें न तो बदला जा सके और न ही यह उन भौतिक पृष्ठों को सुरक्षित रख सके जो परफॉर्मेंस में सुधार कर सकते हैं यदि आपका हार्डवेयर इसका समर्थन कर सकता है।
RandomNickName42

8
@ RandomNickName42: यह सही नहीं है। आबंटन प्रारंभ पता हमेशा ग्रैन्युलैरिटी (64KB) के साथ संरेखित किया जाता है, लेकिन आबंटन की लंबाई पृष्ठ के आकार (4K) तक होती है। वास्तव में, पता स्थान 64KB विखंडू में आरक्षित है, लेकिन 4KB विखंडन में प्रतिबद्ध है। प्रारंभ पते का संरेखण आमतौर पर ऐसा नहीं होता है जो देखने के अधिकांश बिंदुओं से दिलचस्प हो। VirtualAlloc 4KB विखंडू में काम करता है। ये विवरण केवल तब महत्वपूर्ण हो जाते हैं जब आप बहुत सारे छोटे वर्चुअल रोलऑक्स (आप पता स्थान से बाहर चलाएंगे) या कुछ फैंसी (जैसे आसन्न लेकिन अलग-अलग आवंटन) करने की कोशिश कर रहे हैं।
arx

मैंने सोचा कि हेलोकॉल नामक मॉलॉक / नई / सीआरटी ने एक बार अपने स्वयं के एल्गोरिदम का उपयोग किया है जो हेपऑलोक मेमोरी ब्लॉक से मेमोरी के ब्लॉक वापस करने के लिए है?
पॉल जूल

31

मेमोरी एलोकेशन एपीआई (विंडोज में) के बीच के अंतर को समझना बहुत महत्वपूर्ण है यदि आप ऐसी भाषा का उपयोग करने की योजना बनाते हैं, जिसमें मेमोरी प्रबंधन (जैसे सी या सी ++) की आवश्यकता होती है और आईएमएचओ को चित्रित करने का सबसे अच्छा तरीका एक आरेख के साथ है:

यहाँ छवि विवरण दर्ज करें

ध्यान दें कि यह एक बहुत ही सरल, विंडोज-विशिष्ट दृश्य है।

इस आरेख को समझने का तरीका यह है कि आरेख पर एक मेमोरी आवंटन विधि जितनी अधिक है, उच्च स्तर का कार्यान्वयन इसका उपयोग करता है। लेकिन नीचे से शुरू करते हैं।

कर्नेल-मोड मेमोरी मैनेजर

यह ऑपरेटिंग सिस्टम के लिए सभी मेमोरी आरक्षण और आवंटन प्रदान करता है, साथ ही मेमोरी-मैप्ड फ़ाइलों , साझा मेमोरी , कॉपी-ऑन-राइट ऑपरेशन आदि के लिए समर्थन प्रदान करता है , यह सीधे उपयोगकर्ता-मोड कोड से सुलभ नहीं है, इसलिए मैं छोड़ दूंगा यह यहाँ।

VirtualAlloc / VirtualFree

ये उपयोगकर्ता मोड से उपलब्ध सबसे निचले स्तर के एपीआई हैं । समारोह मूल रूप से आह्वान ZwAllocateVirtualMemory बारी में एक त्वरित करता है कि syscall को कर्नेल स्मृति प्रबंधक को आगे की प्रक्रिया के निर्वासित करने के लिए। यह उपयोगकर्ता मोड में उपलब्ध सभी से नई मेमोरी के ब्लॉक को आरक्षित / आवंटित करने का सबसे तेज़ तरीका है।VirtualAllocring0

लेकिन यह दो मुख्य स्थितियों के साथ आता है:

  • यह केवल सिस्टम ग्रैन्युलैरिटी सीमा पर संरेखित मेमोरी ब्लॉक आवंटित करता है।

  • यह केवल आकार के मेमोरी ब्लॉकों को आवंटित करता है जो कि सिस्टम ग्रैन्युलैरिटी के कई हैं।

तो क्या है यह सिस्टम ग्रैन्युलैरिटी ? आप इसे GetSystemInfo पर कॉल करके प्राप्त कर सकते हैं । इसे dwAllocationGranularityपैरामीटर के रूप में लौटाया जाता है । इसका मूल्य कार्यान्वयन (और संभवतः हार्डवेयर) विशिष्ट है, लेकिन कई 64-बिट विंडोज सिस्टम पर यह 0x10000बाइट्स पर सेट है , या 64K

तो इस सबका क्या मतलब है, यदि आप आवंटित करने का प्रयास करते हैं, तो केवल 8 बाइट मेमोरी ब्लॉक के साथ कहें VirtualAlloc:

void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

सफल pAddressहोने पर, 0x10000बाइट सीमा पर गठबंधन किया जाएगा । और भले ही आपने केवल 8 बाइट्स का अनुरोध किया हो, जो वास्तविक मेमोरी ब्लॉक आपको मिलेगा वह संपूर्ण page(या, 4Kबाइट्स जैसा कुछ होगा । सटीक पृष्ठ आकार dwPageSizeपैरामीटर में वापस आ गया है ।) लेकिन, उसके ऊपर, संपूर्ण मेमोरी ब्लॉक। फैले हुए 0x10000बाइट्स (या 64Kज्यादातर मामलों में) किसी भी आगे के आवंटन के लिए उपलब्ध pAddress नहीं होंगे। तो एक तरह से, 8 बाइट्स आवंटित करके आप 65536 मांग सकते हैं।

तो यहां कहानी का नैतिक VirtualAllocआपके आवेदन में जेनेरिक मेमोरी आवंटन के लिए स्थानापन्न नहीं है । इसका उपयोग बहुत विशिष्ट मामलों के लिए किया जाना चाहिए, जैसा कि नीचे दिए गए ढेर के साथ किया जाता है । (आमतौर पर स्मृति के बड़े ब्लॉकों को आरक्षित / आवंटित करने के लिए।)

का उपयोग करते हुए VirtualAllocगलत तरीके से गंभीर स्मृति विखंडन के लिए नेतृत्व कर सकते हैं।

HeapCreate / HeapAlloc / HeapFree / HeapDestroy

संक्षेप में, ढेर कार्य मूल रूप से VirtualAllocफ़ंक्शन के लिए एक आवरण है। यहाँ अन्य उत्तर इसकी बहुत अच्छी अवधारणा प्रदान करते हैं। मैं इसे बहुत ही सरल दृष्टिकोण से जोड़ता हूं, जिस तरह से ढेर काम करता है वह यह है:

  • HeapCreateVirtualAllocआंतरिक रूप से (या ZwAllocateVirtualMemoryविशिष्ट होने के लिए) कॉल करके वर्चुअल मेमोरी का एक बड़ा ब्लॉक सुरक्षित रखता है । यह एक आंतरिक डेटा संरचना भी सेट करता है जो वर्चुअल मेमोरी के आरक्षित ब्लॉक के भीतर छोटे आकार के आवंटन को ट्रैक कर सकता है।

  • करने के लिए किसी भी कॉल HeapAllocऔर HeapFreeवास्तव में आवंटित नहीं है (जब तक, बेशक अनुरोध से अधिक है कि पहले से ही में आरक्षित कर दिया गया है / किसी भी नए स्मृति मुक्त HeapCreate) लेकिन इसके बावजूद वे बाहर मीटर (या commit) एक पहले से ही आरक्षित बड़े हिस्सा, छोटे स्मृति ब्लॉक में यह चीर-फाड़ से कि एक उपयोगकर्ता अनुरोध

  • HeapDestroyबदले में कॉल VirtualFreeजो वास्तव में आभासी मेमोरी को मुक्त करता है।

तो यह सब आपके आवेदन में जेनेरिक मेमोरी आवंटन के लिए ढेर काम करता है । यह मनमाने आकार के मेमोरी आवंटन के लिए बहुत अच्छा है। लेकिन ढेर कार्यों की सुविधा के लिए भुगतान करने के लिए एक छोटी सी कीमत यह है कि वे VirtualAllocस्मृति के बड़े ब्लॉकों को जमा करते समय एक मामूली ओवरहेड का परिचय देते हैं ।

ढेर के बारे में एक और अच्छी बात यह है कि आपको वास्तव में एक बनाने की आवश्यकता नहीं है। यह आम तौर पर आपके लिए बनाया जाता है जब आपकी प्रक्रिया शुरू होती है। तो एक GetProcessHeap फ़ंक्शन को कॉल करके इसे एक्सेस कर सकता है ।

मॉलोक / मुक्त

ढेर कार्यों के लिए एक भाषा-विशिष्ट आवरण है। इसके विपरीत HeapAlloc, HeapFreeआदि ये फ़ंक्शन न केवल आपके कोड को विंडोज के लिए संकलित करने पर काम करेंगे, बल्कि अन्य ऑपरेटिंग सिस्टम (जैसे लिनक्स, आदि) के लिए भी काम करेंगे।

यदि आप सी। में प्रोग्राम करते हैं, तो यह एक मुफ्त तरीका है।

नया / हटाना

स्मृति प्रबंधन ऑपरेटरों के लिए एक उच्च स्तर (अच्छी तरह से C++) के रूप में आओ । वे के लिए विशिष्ट हैं C++भाषा, और तरह mallocके लिए C, यह भी के लिए रैपर हैं heapकाम करता है। उनके पास अपने स्वयं के कोड का एक पूरा गुच्छा होता है C++, जो निर्माणकर्ताओं की विशिष्ट गणना, विध्वंसकों में डीलरशिप, एक अपवाद को बढ़ाता है, आदि।

यदि आप प्रोग्राम करते हैं, तो ये फ़ंक्शंस स्मृति और ऑब्जेक्ट्स को आवंटित / मुक्त करने के लिए एक अनुशंसित तरीका है C++


अंत में, एक टिप्पणी जो मैं चाहता हूं कि VirtualAllocप्रक्रियाओं के बीच स्मृति साझा करने के लिए अन्य प्रतिक्रियाओं में क्या कहा गया है। VirtualAllocअपने आप में अन्य प्रक्रियाओं के साथ अपनी आरक्षित / आवंटित स्मृति को साझा करने की अनुमति नहीं देता है। इसके लिए किसी को CreateFileMappingएपीआई का उपयोग करने की आवश्यकता है जो एक नामित वर्चुअल मेमोरी ब्लॉक बना सकता है जिसे अन्य प्रक्रियाओं के साथ साझा किया जा सकता है। यह रीड / राइट एक्सेस के लिए डिस्क पर एक फ़ाइल को वर्चुअल मेमोरी में मैप कर सकता है। लेकिन वह एक और विषय है।


29

VirtualAllocOS वर्चुअल मेमोरी (VM) प्रणाली का एक विशेष आवंटन है। वीएम प्रणाली में आवंटन एक आवंटन ग्रैन्युलैरिटी पर किया जाना चाहिए जो (आवंटन ग्रैन्युलैरिटी) वास्तुकला पर निर्भर है। VM प्रणाली में आवंटन स्मृति आवंटन के सबसे बुनियादी रूपों में से एक है। वीएम आवंटन कई रूप ले सकता है, मेमोरी आवश्यक रूप से रैम में समर्पित या शारीरिक रूप से समर्थित नहीं है (हालांकि यह हो सकता है)। वीएम आवंटन आम तौर पर आवंटन का एक विशेष उद्देश्य प्रकार है, या तो आवंटन के कारण है

  • बहुत बड़ा हो,
  • साझा करने की आवश्यकता है,
  • एक विशेष मूल्य (प्रदर्शन कारणों) या पर संरेखित किया जाना चाहिए
  • कॉलर को एक बार में इस मेमोरी का उपयोग करने की आवश्यकता नहीं है ...
  • आदि...

HeapAllocअनिवार्य रूप से क्या है mallocऔर newदोनों अंततः कहते हैं। यह एक सामान्य उद्देश्य आवंटन के कई अलग-अलग प्रकार के परिदृश्यों के तहत बहुत तेज और प्रयोग करने योग्य है। यह एक क्लासिक अर्थ में "हीप" है। ढेर वास्तव में एक द्वारा सेटअप कर रहे हैंVirtualAlloc , जो कि ओएस से शुरू में आवंटन स्थान आरक्षित करने के लिए उपयोग किया जाता है । अंतरिक्ष द्वारा आरंभ करने के बाद VirtualAlloc, HEAP के संचालन को बनाए रखने और नियंत्रित करने के लिए विभिन्न तालिकाओं, सूचियों और अन्य डेटा संरचनाओं को कॉन्फ़िगर किया गया है। उस ऑपरेशन में से कुछ गतिशील रूप से आकार (बढ़ते और सिकुड़ते) के रूप में है, ढेर को विशेष उपयोग (कुछ आकार के लगातार आवंटन), आदि के लिए अनुकूल बनाना।

newऔर mallocकुछ हद तक समान हैं, mallocअनिवार्य रूप से एक सटीक कॉल है HeapAlloc( heap-id-default );newहालाँकि, C ++ ऑब्जेक्ट्स के लिए आवंटित मेमोरी कॉन्फ़िगर कर सकता है । किसी दिए गए ऑब्जेक्ट के लिए, C ++ प्रत्येक कॉलर के लिए ढेर पर vtables स्टोर करेगा। ये vtables निष्पादन के लिए पुनर्निर्देशित होते हैं और सी + + के भाग का निर्माण करते हैं, जो इनहेरिटेंस, फंक्शन ओवरलोडिंग, आदि जैसी OO विशेषताएँ हैं ...

जैसे कुछ अन्य आम आवंटन के तरीकों _alloca()और _malloca()हैं ढेर आधारित है; FileMappings वास्तव में के साथ आवंटित कर रहे हैंVirtualAlloc विशेष प्रकार के झंडे के साथ और सेट जो उन मैपिंग को प्रकार के होते हैं FILE

अधिकांश समय, आपको मेमोरी को एक तरह से आवंटित करना चाहिए जो उस मेमोरी के उपयोग के अनुरूप है;)। newC ++ में,malloc C के लिए, VirtualAllocबड़े पैमाने पर या IPC मामलों के लिए।

*** ध्यान दें, बड़े स्मृति आवंटन HeapAllocवास्तव में बंद करने के लिए भेज रहे हैंVirtualAlloc कुछ आकार (युगल सौ के या 16 एमबी या कुछ मैं भूल जाते हैं, लेकिन काफी बड़ा :)) के बाद ।

*** EDIT I ​​ने संक्षेप में IPC के बारे में टिप्पणी की और VirtualAlloc, वहाँ भी एक संबंधित के बारे में बहुत साफ-सुथरा है, VirtualAllocजिसके बारे में इस प्रश्न के उत्तरदाताओं में से किसी ने भी चर्चा नहीं की है।

VirtualAllocपूर्व वह है जो एक प्रक्रिया एक अलग प्रक्रिया के पते स्थान में मेमोरी आवंटित करने के लिए उपयोग कर सकती है। आमतौर पर, इसका उपयोग CreateRemoteThread (इसी तरह , थ्रेड अन्य प्रक्रिया में चलाया जाता है) के माध्यम से किसी अन्य प्रक्रिया के संदर्भ में दूरस्थ निष्पादन प्राप्त करने के लिए किया जाता हैCreateThread


7

मोटे तौर पर:

  • VirtualAlloc, HeapAlloc आदि विंडोज एपीआई हैं जो सीधे ओएस से विभिन्न प्रकार की मेमोरी आवंटित करते हैं। VirtualAlloc Windows वर्चुअल मेमोरी सिस्टम में पृष्ठों का प्रबंधन करता है, जबकि HeapAlloc एक विशिष्ट OS हीप से आवंटित करता है। सच कहूँ तो, आप उनमें से कभी भी उपयोग करने की आवश्यकता की संभावना नहीं है।

  • Malloc एक मानक C (और C ++) लाइब्रेरी फ़ंक्शन है जो आपकी प्रक्रिया को मेमोरी आवंटित करता है। जब आपका ऐप शुरू होता है और उसके बाद जब आप मॉलॉक अनुरोध करते हैं, तो मॉलॉक के कार्यान्वयन में आमतौर पर ओएस एपीआई में से एक का उपयोग करके मेमोरी का एक पूल बनाया जाएगा।

  • new एक Standard C ++ ऑपरेटर है जो मेमोरी आवंटित करता है और फिर कंस्ट्रक्टर्स को उस मेमोरी पर उचित कॉल करता है। यह मॉलॉक के संदर्भ में या ओएस एपीआई के संदर्भ में लागू किया जा सकता है, इस स्थिति में यह आमतौर पर एप्लिकेशन स्टार्टअप पर एक मेमोरी पूल बनाएगा।



2

VirtualAlloc=> आभासी मेमोरी में सीधे आवंटन, आप ब्लॉकों में आरक्षित / प्रतिबद्ध करते हैं। यह बड़े आवंटन के लिए महान है, उदाहरण के लिए बड़ी सरणियाँ।

HeapAlloc/ new=> डिफॉल्ट हीप (या आपके द्वारा बनाया जा सकने वाला कोई अन्य हीप) पर मेमोरी आवंटित करता है। यह प्रति ऑब्जेक्ट आवंटित करता है और छोटी वस्तुओं के लिए महान है। डिफॉल्ट हीप सीरियल करने योग्य है, इसलिए इसमें थ्रेड आवंटन की गारंटी है (यह उच्च प्रदर्शन परिदृश्यों पर कुछ मुद्दों का कारण बन सकता है और इसीलिए आप अपने स्वयं के ढेर बना सकते हैं)।

malloc=> सी रनटाइम हीप का उपयोग करता है, HeapAllocलेकिन यह संगतता परिदृश्यों के लिए सामान्य है।

संक्षेप में, ढेर केवल आभासी मेमोरी का एक हिस्सा है जो एक हीप मैनेजर द्वारा संचालित होता है (बजाय कच्चे आभासी कंप्यूटर के)

मेमोरी वर्ल्ड पर अंतिम मॉडल मेमोरी मैप्ड फाइलें हैं, यह परिदृश्य डेटा के बड़े हिस्से (बड़ी फ़ाइलों की तरह) के लिए बहुत अच्छा है। इसका उपयोग आंतरिक रूप से तब किया जाता है जब आप एक EXE खोलते हैं (यह EXE को मेमोरी में लोड नहीं करता है, बस एक मेमोरी मैप्ड फ़ाइल बनाता है)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.