वहाँ इस तरह के रूप Windows वातावरण में स्मृति को आबंटित करने विधि के बहुत सारे हैं VirtualAlloc
, HeapAlloc
, malloc
, new
।
इस प्रकार, उनमें क्या अंतर है?
जवाबों:
प्रत्येक एपीआई विभिन्न उपयोगों के लिए है। हर एक को यह भी आवश्यक है कि जब आप मेमोरी के साथ काम कर रहे हों तो आप सही डीलक्लोलेशन / फ्रीजिंग फंक्शन का उपयोग करें।
एक निम्न-स्तरीय, विंडोज एपीआई जो बहुत सारे विकल्प प्रदान करता है, लेकिन मुख्य रूप से काफी विशिष्ट स्थितियों में लोगों के लिए उपयोगी है। केवल मेमोरी को आवंटित कर सकते हैं (संपादित करें: 4KB नहीं) बड़ा हिस्सा। ऐसी परिस्थितियाँ हैं जहाँ आपको इसकी आवश्यकता होती है, लेकिन जब आप इन स्थितियों में से एक में होंगे तब आपको पता चल जाएगा। सबसे आम में से एक है यदि आपको किसी अन्य प्रक्रिया के साथ सीधे मेमोरी साझा करना है। सामान्य प्रयोजन स्मृति आवंटन के लिए इसका उपयोग न करें। VirtualFree
डीलकोलेट करने के लिए उपयोग करें ।
आप जो भी मेमोरी मांगते हैं, उससे बड़ी मात्रा में नहीं, आवंटित करता है VirtualAlloc
। HeapAlloc
यह जानता है कि कॉल करने की आवश्यकता कब होती है VirtualAlloc
और आपके लिए यह स्वचालित रूप से होता है। जैसे malloc
, लेकिन केवल Windows है, और कुछ और विकल्प प्रदान करता है। स्मृति के सामान्य भाग को आवंटित करने के लिए उपयुक्त है। कुछ विंडोज एपीआई की आवश्यकता हो सकती है कि आप इसका उपयोग उन मेमोरी को आवंटित करने के लिए करते हैं जो आप उनके पास जाते हैं, या अपने साथी HeapFree
को मुफ्त मेमोरी में उपयोग करते हैं जो वे आपके पास लौटते हैं।
स्मृति को आवंटित करने का सी तरीका। इसे प्राथमिकता दें यदि आप C ++ के बजाय C में लिख रहे हैं, और आप चाहते हैं कि आपका कोड उदा यूनिक्स कंप्यूटर पर भी काम करे, या कोई व्यक्ति विशेष रूप से कहता है कि आपको इसका उपयोग करने की आवश्यकता है। मेमोरी को इनिशियलाइज़ नहीं करता है। स्मृति के सामान्य विखंडू को आवंटित करने के लिए उपयुक्त है, जैसे HeapAlloc
। एक साधारण एपीआई। free
डीलकोलेट करने के लिए उपयोग करें । विजुअल C ++ की malloc
कॉल HeapAlloc
।
मेमोरी आवंटित करने का C ++ तरीका। इसे प्राथमिकता दें यदि आप C ++ में लिख रहे हैं। यह किसी ऑब्जेक्ट या ऑब्जेक्ट को आवंटित मेमोरी में भी डालता है। delete
डीललॉकेट (या delete[]
सरणियों के लिए) का उपयोग करें । विज़ुअल स्टूडियो के new
कॉल HeapAlloc
, और फिर ऑब्जेक्ट को इनिशियलाइज़ करते हैं, इस पर निर्भर करता है कि आप इसे कैसे कहते हैं।
हाल ही में सी ++ मानकों (सी ++ 11 और उससे अधिक) के लिए आपको मैन्युअल उपयोग करने के लिए है, तो delete
, आप गलत कर रहे हैं और एक का उपयोग करना चाहिए स्मार्ट सूचक की तरह unique_ptr
बजाय। C ++ 14 के बाद से, उसी के बारे में कहा जा सकता है new
(जैसे कार्यों के साथ प्रतिस्थापित make_unique()
)।
कुछ अन्य समान कार्य भी हैं जैसे SysAllocString
कि आपको बताया जा सकता है कि आपको विशिष्ट परिस्थितियों में उपयोग करना है।
मेमोरी एलोकेशन एपीआई (विंडोज में) के बीच के अंतर को समझना बहुत महत्वपूर्ण है यदि आप ऐसी भाषा का उपयोग करने की योजना बनाते हैं, जिसमें मेमोरी प्रबंधन (जैसे सी या सी ++) की आवश्यकता होती है और आईएमएचओ को चित्रित करने का सबसे अच्छा तरीका एक आरेख के साथ है:
ध्यान दें कि यह एक बहुत ही सरल, विंडोज-विशिष्ट दृश्य है।
इस आरेख को समझने का तरीका यह है कि आरेख पर एक मेमोरी आवंटन विधि जितनी अधिक है, उच्च स्तर का कार्यान्वयन इसका उपयोग करता है। लेकिन नीचे से शुरू करते हैं।
यह ऑपरेटिंग सिस्टम के लिए सभी मेमोरी आरक्षण और आवंटन प्रदान करता है, साथ ही मेमोरी-मैप्ड फ़ाइलों , साझा मेमोरी , कॉपी-ऑन-राइट ऑपरेशन आदि के लिए समर्थन प्रदान करता है , यह सीधे उपयोगकर्ता-मोड कोड से सुलभ नहीं है, इसलिए मैं छोड़ दूंगा यह यहाँ।
ये उपयोगकर्ता मोड से उपलब्ध सबसे निचले स्तर के एपीआई हैं । समारोह मूल रूप से आह्वान ZwAllocateVirtualMemory बारी में एक त्वरित करता है कि syscall को कर्नेल स्मृति प्रबंधक को आगे की प्रक्रिया के निर्वासित करने के लिए। यह उपयोगकर्ता मोड में उपलब्ध सभी से नई मेमोरी के ब्लॉक को आरक्षित / आवंटित करने का सबसे तेज़ तरीका है।VirtualAlloc
ring0
लेकिन यह दो मुख्य स्थितियों के साथ आता है:
यह केवल सिस्टम ग्रैन्युलैरिटी सीमा पर संरेखित मेमोरी ब्लॉक आवंटित करता है।
यह केवल आकार के मेमोरी ब्लॉकों को आवंटित करता है जो कि सिस्टम ग्रैन्युलैरिटी के कई हैं।
तो क्या है यह सिस्टम ग्रैन्युलैरिटी ? आप इसे 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
गलत तरीके से गंभीर स्मृति विखंडन के लिए नेतृत्व कर सकते हैं।
संक्षेप में, ढेर कार्य मूल रूप से VirtualAlloc
फ़ंक्शन के लिए एक आवरण है। यहाँ अन्य उत्तर इसकी बहुत अच्छी अवधारणा प्रदान करते हैं। मैं इसे बहुत ही सरल दृष्टिकोण से जोड़ता हूं, जिस तरह से ढेर काम करता है वह यह है:
HeapCreate
VirtualAlloc
आंतरिक रूप से (या ZwAllocateVirtualMemory
विशिष्ट होने के लिए) कॉल करके वर्चुअल मेमोरी का एक बड़ा ब्लॉक सुरक्षित रखता है । यह एक आंतरिक डेटा संरचना भी सेट करता है जो वर्चुअल मेमोरी के आरक्षित ब्लॉक के भीतर छोटे आकार के आवंटन को ट्रैक कर सकता है।
करने के लिए किसी भी कॉल HeapAlloc
और HeapFree
वास्तव में आवंटित नहीं है (जब तक, बेशक अनुरोध से अधिक है कि पहले से ही में आरक्षित कर दिया गया है / किसी भी नए स्मृति मुक्त HeapCreate
) लेकिन इसके बावजूद वे बाहर मीटर (या commit
) एक पहले से ही आरक्षित बड़े हिस्सा, छोटे स्मृति ब्लॉक में यह चीर-फाड़ से कि एक उपयोगकर्ता अनुरोध
HeapDestroy
बदले में कॉल VirtualFree
जो वास्तव में आभासी मेमोरी को मुक्त करता है।
तो यह सब आपके आवेदन में जेनेरिक मेमोरी आवंटन के लिए ढेर काम करता है । यह मनमाने आकार के मेमोरी आवंटन के लिए बहुत अच्छा है। लेकिन ढेर कार्यों की सुविधा के लिए भुगतान करने के लिए एक छोटी सी कीमत यह है कि वे VirtualAlloc
स्मृति के बड़े ब्लॉकों को जमा करते समय एक मामूली ओवरहेड का परिचय देते हैं ।
ढेर के बारे में एक और अच्छी बात यह है कि आपको वास्तव में एक बनाने की आवश्यकता नहीं है। यह आम तौर पर आपके लिए बनाया जाता है जब आपकी प्रक्रिया शुरू होती है। तो एक GetProcessHeap फ़ंक्शन को कॉल करके इसे एक्सेस कर सकता है ।
ढेर कार्यों के लिए एक भाषा-विशिष्ट आवरण है। इसके विपरीत HeapAlloc
, HeapFree
आदि ये फ़ंक्शन न केवल आपके कोड को विंडोज के लिए संकलित करने पर काम करेंगे, बल्कि अन्य ऑपरेटिंग सिस्टम (जैसे लिनक्स, आदि) के लिए भी काम करेंगे।
यदि आप सी। में प्रोग्राम करते हैं, तो यह एक मुफ्त तरीका है।
स्मृति प्रबंधन ऑपरेटरों के लिए एक उच्च स्तर (अच्छी तरह से C++
) के रूप में आओ । वे के लिए विशिष्ट हैं C++
भाषा, और तरह malloc
के लिए C
, यह भी के लिए रैपर हैं heap
काम करता है। उनके पास अपने स्वयं के कोड का एक पूरा गुच्छा होता है C++
, जो निर्माणकर्ताओं की विशिष्ट गणना, विध्वंसकों में डीलरशिप, एक अपवाद को बढ़ाता है, आदि।
यदि आप प्रोग्राम करते हैं, तो ये फ़ंक्शंस स्मृति और ऑब्जेक्ट्स को आवंटित / मुक्त करने के लिए एक अनुशंसित तरीका है C++
।
अंत में, एक टिप्पणी जो मैं चाहता हूं कि VirtualAlloc
प्रक्रियाओं के बीच स्मृति साझा करने के लिए अन्य प्रतिक्रियाओं में क्या कहा गया है। VirtualAlloc
अपने आप में अन्य प्रक्रियाओं के साथ अपनी आरक्षित / आवंटित स्मृति को साझा करने की अनुमति नहीं देता है। इसके लिए किसी को CreateFileMapping
एपीआई का उपयोग करने की आवश्यकता है जो एक नामित वर्चुअल मेमोरी ब्लॉक बना सकता है जिसे अन्य प्रक्रियाओं के साथ साझा किया जा सकता है। यह रीड / राइट एक्सेस के लिए डिस्क पर एक फ़ाइल को वर्चुअल मेमोरी में मैप कर सकता है। लेकिन वह एक और विषय है।
VirtualAlloc
OS वर्चुअल मेमोरी (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
।
अधिकांश समय, आपको मेमोरी को एक तरह से आवंटित करना चाहिए जो उस मेमोरी के उपयोग के अनुरूप है;)। new
C ++ में,malloc
C के लिए, VirtualAlloc
बड़े पैमाने पर या IPC मामलों के लिए।
*** ध्यान दें, बड़े स्मृति आवंटन HeapAlloc
वास्तव में बंद करने के लिए भेज रहे हैंVirtualAlloc
कुछ आकार (युगल सौ के या 16 एमबी या कुछ मैं भूल जाते हैं, लेकिन काफी बड़ा :)) के बाद ।
*** EDIT I ने संक्षेप में IPC के बारे में टिप्पणी की और VirtualAlloc
, वहाँ भी एक संबंधित के बारे में बहुत साफ-सुथरा है, VirtualAlloc
जिसके बारे में इस प्रश्न के उत्तरदाताओं में से किसी ने भी चर्चा नहीं की है।
VirtualAlloc
पूर्व वह है जो एक प्रक्रिया एक अलग प्रक्रिया के पते स्थान में मेमोरी आवंटित करने के लिए उपयोग कर सकती है। आमतौर पर, इसका उपयोग CreateRemoteThread (इसी तरह , थ्रेड अन्य प्रक्रिया में चलाया जाता है) के माध्यम से किसी अन्य प्रक्रिया के संदर्भ में दूरस्थ निष्पादन प्राप्त करने के लिए किया जाता है ।CreateThread
मोटे तौर पर:
VirtualAlloc, HeapAlloc आदि विंडोज एपीआई हैं जो सीधे ओएस से विभिन्न प्रकार की मेमोरी आवंटित करते हैं। VirtualAlloc Windows वर्चुअल मेमोरी सिस्टम में पृष्ठों का प्रबंधन करता है, जबकि HeapAlloc एक विशिष्ट OS हीप से आवंटित करता है। सच कहूँ तो, आप उनमें से कभी भी उपयोग करने की आवश्यकता की संभावना नहीं है।
Malloc एक मानक C (और C ++) लाइब्रेरी फ़ंक्शन है जो आपकी प्रक्रिया को मेमोरी आवंटित करता है। जब आपका ऐप शुरू होता है और उसके बाद जब आप मॉलॉक अनुरोध करते हैं, तो मॉलॉक के कार्यान्वयन में आमतौर पर ओएस एपीआई में से एक का उपयोग करके मेमोरी का एक पूल बनाया जाएगा।
new एक Standard C ++ ऑपरेटर है जो मेमोरी आवंटित करता है और फिर कंस्ट्रक्टर्स को उस मेमोरी पर उचित कॉल करता है। यह मॉलॉक के संदर्भ में या ओएस एपीआई के संदर्भ में लागू किया जा सकता है, इस स्थिति में यह आमतौर पर एप्लिकेशन स्टार्टअप पर एक मेमोरी पूल बनाएगा।
VirtualAlloc
===> sbrk()
यूनिक्स के तहत
HeapAlloc
====> malloc()
यूनिक्स के तहत
VirtualAlloc
=> आभासी मेमोरी में सीधे आवंटन, आप ब्लॉकों में आरक्षित / प्रतिबद्ध करते हैं। यह बड़े आवंटन के लिए महान है, उदाहरण के लिए बड़ी सरणियाँ।
HeapAlloc
/ new
=> डिफॉल्ट हीप (या आपके द्वारा बनाया जा सकने वाला कोई अन्य हीप) पर मेमोरी आवंटित करता है। यह प्रति ऑब्जेक्ट आवंटित करता है और छोटी वस्तुओं के लिए महान है। डिफॉल्ट हीप सीरियल करने योग्य है, इसलिए इसमें थ्रेड आवंटन की गारंटी है (यह उच्च प्रदर्शन परिदृश्यों पर कुछ मुद्दों का कारण बन सकता है और इसीलिए आप अपने स्वयं के ढेर बना सकते हैं)।
malloc
=> सी रनटाइम हीप का उपयोग करता है, HeapAlloc
लेकिन यह संगतता परिदृश्यों के लिए सामान्य है।
संक्षेप में, ढेर केवल आभासी मेमोरी का एक हिस्सा है जो एक हीप मैनेजर द्वारा संचालित होता है (बजाय कच्चे आभासी कंप्यूटर के)
मेमोरी वर्ल्ड पर अंतिम मॉडल मेमोरी मैप्ड फाइलें हैं, यह परिदृश्य डेटा के बड़े हिस्से (बड़ी फ़ाइलों की तरह) के लिए बहुत अच्छा है। इसका उपयोग आंतरिक रूप से तब किया जाता है जब आप एक EXE खोलते हैं (यह EXE को मेमोरी में लोड नहीं करता है, बस एक मेमोरी मैप्ड फ़ाइल बनाता है)।