2015-10-30 7 views
11

चलिए इस सी ++ कोड को किसी न किसी उदाहरण के रूप में देखते हैं।सी ++ आवंटित सरणी गैर-संयोग से

int *A = new int [5]; 
int *B = new int [5]; 
int *C = new int [5]; 
delete []A; 
delete []C; 
int *D = new int [10]; 

जाहिर है किसी भी मशीन बफर अतिप्रवाह या स्मृति रिसाव के साथ किसी भी समस्याओं के बिना इस मामले को संभाल सकता है। हालांकि आइए कल्पना करें कि लंबाई एक लाख या इससे भी बड़ी संख्या में गुणा हो जाती है। जहां तक ​​मुझे पता है कि सभी सरणी तत्वों के पते (कम से कम आभासी पते) लगातार हैं। इसलिए जब भी मैं एक सरणी बनाता हूं, तो मैं यह सुनिश्चित कर सकता हूं कि वे वर्चुअल मेमोरी में संगत भाग हैं और मैं पॉइंटर अंकगणित को एन-वें तत्व तक पहुंचने के लिए कर सकता हूं यदि मेरे पास पहले पॉइंटर है। मेरा प्रश्न निम्नलिखित छवि में दिखाया गया है (सरणी के अंत के लिए सरणी के अंत का प्रतिनिधित्व करने वाले रजिस्टरों को अनदेखा किया जाता है)। heap array allocation

ढेर में ए, बी, सी आवंटित करने के बाद हम ए और सी मुक्त करते हैं और लंबाई 5 के दो मुक्त मेमोरी भाग प्राप्त करते हैं (हरे रंग के बिंदुओं के साथ चिह्नित)। क्या होता है जब मैं लंबाई 10 की आवंटित करना चाहता हूं? मुझे लगता है कि 3 संभावित मामले हैं।

  • मुझे 10 गुना स्मृति खंड न होने के लिए bad_alloc अपवाद मिलेगा।
  • प्रोग्राम स्वचालित रूप से ढेर की शुरुआत में सरणी बी को पुन: आवंटित करेगा और शेष अप्रयुक्त स्मृति में एक साथ जुड़ जाएगा।
  • सरणी डी को 2 भागों में विभाजित किया जाएगा और सरणी के एन-वें तत्व के लिए निरंतर पहुंच समय नहीं होने के कारण संग्रहीत नहीं किया जाता है (यदि 2 से अधिक विभाजन होते हैं तो यह एक सरणी के बजाय एक लिंक्ड सूची जैसा दिखता है)।

    इनमें से कौन सा सबसे संभावित उत्तर है या क्या कोई और संभावित मामला मैंने ध्यान में नहीं लिया है?

+9

यह बहुत ओएस निर्भर है। –

+1

@JamesAdkison हां, मान लें कि हमारे पास हीप मेमोरी के केवल 15 रजिस्ट्रार हैं। अन्यथा सवाल व्यर्थ होगा। –

+2

यह इस तथ्य को भी अनदेखा करता है कि प्रोग्राम * वर्चुअल * मेमोरी * के विपरीत * भौतिक हार्डवेयर मेमोरी * का उपयोग करते हैं। यह एक सैद्धांतिक सवाल है। सैद्धांतिक उत्तर 'नई' या 'malloc' को उपलब्ध स्मृति से अधिक के लिए बाद के अनुरोध पर 'NULL' वापस करने की अपेक्षा करना होगा। –

उत्तर

6

मुझे 10 गुना स्मृति खंड न होने के लिए bad_alloc अपवाद मिलेगा।

ऐसा हो सकता है।

प्रोग्राम स्वचालित रूप से ढेर की शुरुआत में सरणी बी को पुन: आवंटित करेगा और शेष अप्रयुक्त स्मृति में एक साथ जुड़ जाएगा।

ऐसा नहीं हो सकता है। किसी ऑब्जेक्ट को किसी भिन्न पते पर ले जाना C++ में संभव नहीं है क्योंकि यह मौजूदा पॉइंटर्स को अमान्य कर देगा।

सरणी डी 2 भागों में विभाजित किया जाएगा और संग्रहीत समीपवर्ती सरणी के एन-वें तत्व के लिए स्थिर नहीं उपयोग समय के कारण नहीं (यदि वहाँ ज्यादा 2 की तुलना में अधिक विभाजन यह एक लिंक्ड सूची सदृश बजाय शुरू होता हैं एक सरणी)।

यह भी नहीं हो सकता है। सी ++ सरणी तत्वों में संगत रूप से संग्रहीत किया जाता है, ताकि सूचक अंकगणित संभव हो।

लेकिन वास्तव में और अधिक संभावनाएं हैं। उन्हें समझने के लिए, हमें इस तथ्य के लिए जिम्मेदार होना चाहिए कि स्मृति आभासी हो सकती है। यह, अन्य चीजों के साथ, इसका मतलब है कि उपलब्ध पता स्थान भौतिक रूप से वर्तमान स्मृति की मात्रा से बड़ा हो सकता है। भौतिक स्मृति का एक हिस्सा उपलब्ध पता स्थान से कोई पता आवंटित किया जा सकता है।

उदाहरण के तौर पर, 64-बिट CPU पर 64-बिट ओएस चलाने वाली स्मृति के 8 जीबी (2^33 बाइट्स) वाली मशीन पर विचार करें। कार्यक्रम में आवंटित पते को 8 जीबी से कम नहीं दिया गया है; यह 0x00000000ffff0000 पते पर स्मृति का मेगाबाइट हिस्सा प्राप्त कर सकता है और 0x0000ffffffff0000 पते पर एक और मेगाबाइट खंड प्राप्त कर सकता है। कार्यक्रम में आवंटित स्मृति की कुल राशि 2^33 बाइट से अधिक नहीं हो सकती है, लेकिन प्रत्येक खंड 2^64 स्पेस में कहीं भी स्थित हो सकता है। (हकीकत में यह थोड़ा और जटिल है लेकिन मैं जो वर्णन करता हूं उसके समान ही)।

आपकी तस्वीर में, आपके पास 15 छोटे वर्ग हैं जो स्मृति के भाग का प्रतिनिधित्व करते हैं। मान लें कि यह भौतिक स्मृति है। वर्चुअल मेमोरी 15,000 छोटे वर्ग हैं, जिनमें से आप किसी भी समय किसी भी 15 का उपयोग कर सकते हैं।

तो, इस तथ्य पर विचार करते हुए, निम्नलिखित परिदृश्य भी संभव हैं।

  • वर्चुअल एड्रेस स्पेस का एक हिस्सा प्रोग्राम को दिया जाता है जो वास्तविक भौतिक स्मृति द्वारा समर्थित नहीं है। जब और यदि प्रोग्राम इस स्पेस तक पहुंचने का प्रयास करता है, तो ओएस भौतिक स्मृति आवंटित करने और इसे संबंधित पते पर मैप करने का प्रयास करेगा ताकि प्रोग्राम जारी रख सके।यदि यह प्रयास विफल रहता है, तो प्रोग्राम ओएस द्वारा मारा जा सकता है। नव-मुक्त स्मृति अब उन अन्य कार्यक्रमों के लिए उपलब्ध है जो इसे चाहें।
  • स्मृति के दो छोटे भाग नए वर्चुअल पतों पर मैप किए जाते हैं जैसे कि वे वर्चुअल मेमोरी स्पेस में एक लंबे संगत खंड बनाते हैं। याद रखें कि आमतौर पर भौतिक स्मृति की तुलना में कई और वर्चुअल मेमोरी पतों हैं, और एक असाइन किए गए रेंज को ढूंढना आम तौर पर आसान होता है। आम तौर पर इस परिदृश्य को केवल तभी महसूस किया जाता है जब प्रश्न में स्मृति भाग बड़े होते हैं।
7

जिस समस्या के बारे में आप पूछ रहे हैं उसे ढेर-विखंडन कहा जाता है, और यह वास्तविक, कठिन समस्या है।

मुझे 10 गुना स्मृति खंड न होने के लिए bad_alloc अपवाद मिलेगा।

यह सिद्धांत है। लेकिन ऐसी स्थिति केवल 32-बिट प्रक्रिया के भीतर ही संभव है; 64-बिट पता स्थान विशाल है।

यह 64-बिट प्रक्रिया के साथ है, यह अधिक संभावना है कि ढेर विखंडन आपके new कार्यान्वयन को कुछ स्मृति का पुन: उपयोग करने से रोकता है, जिससे स्मृति की स्थिति बढ़ जाती है क्योंकि इसे कर्नेल से नई मेमोरी के लिए पूछना पड़ता है इसके आधे के बजाय पूरे D सरणी के लिए। इसके अलावा, ओओएम-किलर द्वारा आपकी प्रक्रिया को D में किसी स्थान तक पहुंचने का प्रयास करने की संभावना अधिक होने की संभावना है, क्योंकि new अपवाद फेंकने के बजाय, क्योंकि कर्नेल को यह नहीं पता होगा कि यह अतिसंवेदनशील है बहुत देर हो चुकी है इससे पहले इसकी याददाश्त। अधिक जानकारी के लिए, Google "स्मृति ओवरकमिटमेंट"।

प्रोग्राम स्वचालित रूप से ढेर की शुरुआत में सरणी बी को पुन: आवंटित करेगा और शेष अप्रयुक्त स्मृति में एक साथ जुड़ जाएगा।

नहीं, यह नहीं हो सकता है।आप सी ++ में हैं, और आपका रनटाइम यह नहीं जानता कि आपने संभवतः B पर पॉइंटर्स को संग्रहीत किया है, इसलिए यह एक पॉइंटर को याद करने का खतरा चलाएगा जिसे संशोधित करने की आवश्यकता है या B पर पॉइंटर नहीं है जो कुछ संशोधित करने का खतरा चलाएगा लेकिन एक ही बिट पैटर्न होता है।

सरणी डी 2 भागों में विभाजित किया जाएगा और संग्रहीत समीपवर्ती सरणी के एन-वें तत्व के लिए स्थिर नहीं उपयोग समय के कारण नहीं (यदि वहाँ ज्यादा 2 की तुलना में अधिक विभाजन यह एक लिंक्ड सूची सदृश बजाय शुरू होता हैं एक सरणी)।

यह भी संभव नहीं है क्योंकि सी ++ सरणी के संगत भंडारण की गारंटी देता है (सरणी को पॉइंटर अंकगणितीय के माध्यम से लागू करने की अनुमति देता है)।

+0

मेमोरी ओवरकमिटमेंट केवल कुछ ओएस पर होता है, और केवल तभी जब आप 'ulimit' या ऐसे कुछ टूल के माध्यम से प्रोग्राम में उपलब्ध स्मृति को समझदारी से सीमित नहीं करते हैं। –

+0

@ एनएम। सच है, लेकिन कम से कम यह सभी लिनक्स प्रतिष्ठानों को प्रभावित करता है, जिसका अर्थ है कि कंप्यूटिंग उपकरणों का विशाल बहुमत स्मृति अतिसंवेदनशीलता करता है। मैं खिड़कियों के बारे में नहीं जानता, हालांकि; क्या वे स्मृति अतिसंवेदनशीलता भी नहीं करते हैं? – cmaster

+0

एंबेडेड डिवाइस आमतौर पर ओवरकमिटमेंट बंद हो जाते हैं (या कम से कम उन्हें चाहिए!) –

संबंधित मुद्दे