2016-01-13 5 views
7

के साथ असफल होने के बाद सफल होता है मैंने ढेर आकार का अनुमान लगाने के लिए एक छोटा सा प्रोग्राम लिखा था (मुझे पता है कि शायद मैं इसे सिर्फ गुगल कर सकता हूं, लेकिन यह अधिक मजेदार लग रहा था और मैंने सोचा कि यह एक त्वरित सरल बात होगी)।मॉलोक कोई मुफ्त

इस पूरे कार्यक्रम है:

#include <stdio.h> 
#include <stdlib.h> 

void main() 
{ 
    unsigned long long alloc_size = 1024; 
    unsigned long long total = 0; 
    unsigned int i = 0; 
    void* p = 0; 

    while(alloc_size >= 16) { 
     p = malloc(alloc_size); 
     if (p) { 
      total += alloc_size; 
      i++; 
      printf("%u)\tAllocated %llu bytes\tTotal so far %llu\n", i, alloc_size, total); 
      alloc_size *= 2; 
     } 
     else { 
      alloc_size /= 2; 
     } 
    } 
    printf("Total alloctions: %llu bytes in %u allocations", total, i); 
} 

मैं इस भाग गया, और 2 बातें से आश्चर्यचकित था:

  1. परिणाम असंगत थी। यदि मैं इसे कई बार चलाता हूं, तो मुझे बिल्कुल वही परिणाम नहीं मिलता है। वर्चुअल मेमोरी मॉडल (या जिसे भी कहा जाता है) के लिए धन्यवाद, क्या यह निर्धारक नहीं होना चाहिए?
  2. चूंकि प्रोग्राम कभी भी स्मृति को मुक्त नहीं करता है, इसलिए मैं उम्मीद करता हूं कि यदि एक निश्चित आकार के लिए एक मॉलोक एक बार विफल हो जाता है, तो यह अचानक बाद में सफल नहीं होगा, लेकिन - आश्चर्य! यहां कार्यक्रम में से एक रन से एक नमूना, और कभी-कभी मैं अलग हो गया है (देखें # 1), लेकिन इसी तरह के परिणाम है:
42)  Allocated 65536 bytes Total so far 28337044480 
43)  Allocated 16384 bytes Total so far 28337060864 
44)  Allocated 16384 bytes Total so far 28337077248 
45)  Allocated 16384 bytes Total so far 28337093632 
46)  Allocated 16384 bytes Total so far 28337110016 
47)  Allocated 32768 bytes Total so far 28337142784 
48)  Allocated 8192 bytes Total so far 28337150976 
49)  Allocated 8192 bytes Total so far 28337159168 
50)  Allocated 16384 bytes Total so far 28337175552 
51)  Allocated 32768 bytes Total so far 28337208320 
52)  Allocated 65536 bytes Total so far 28337273856 
53)  Allocated 131072 bytes Total so far 28337404928 
54)  Allocated 262144 bytes Total so far 28337667072 
55)  Allocated 16384 bytes Total so far 28337683456 
56)  Allocated 8192 bytes Total so far 28337691648 
57)  Allocated 4096 bytes Total so far 28337695744 

आप देख सकते हैं, इस के बाद यह पहले से ही शिखर आवंटन पर पहुंच गया है आकार और इस तरह से नीचे है। आवंटन # 42 और # 43 के बीच, यह 32768 बाइट आवंटित करने की कोशिश करता और असफल रहा। आवंटन के बाद # 43 - # 45। तो अचानक यह # 47 पर कैसे प्रबंधित किया? आप एक ही चीज़ # 50 - # 54 पर देख सकते हैं। और यह केवल एक नमूना है। इस विशेष दौड़ में कुल 272 आवंटन में यह वही व्यवहार कई बार हुआ।

मुझे आशा है कि यह लंबे समय तक नहीं था, लेकिन मैं वास्तव में उलझन में हूं और इस पर किसी भी प्रकाश शेड के लिए खुश होगा।

संपादित
मुझे लगता है कि इस MinGW-W64 64 बिट जीसीसी संकलक के साथ एक Win7 64 बिट मशीन पर है जोड़ना चाहिए, कोई संकलक झंडे

+0

'malloc()' विफल क्यों होगा? और कुछ अन्य प्रक्रियाओं के बाद "मुक्त 'डीडी मेमोरी के बाद यह सफल क्यों नहीं होगा? कृपया समझाओ * बिल्कुल वही परिणाम *? –

+0

@iharob 'malloc' असफल हो जाएगा अगर यह आवश्यक मात्रा में स्मृति (स्मृति से बाहर) आवंटित नहीं कर सका। वर्चुअल मेमोरी मॉडल (यदि मैं इसे सही ढंग से समझता हूं) का अर्थ है कि मेरे प्रोग्राम मेमोरी आवंटन अन्य कार्यक्रमों से पूरी तरह से अलग हैं। – baruch

+1

यह संभवतः आधुनिक ओएस पर काम नहीं करेगा ("आशावादी आवंटन" देखें)। भले ही, यह गारंटी नहीं देता है कि यह बाद में उपलब्ध होगा। बस जो भी आपको चाहिए उसे आवंटित करें और उपलब्ध न होने पर विफल हो जाएं। अपने ओएस को आउटमार्ट करने की कोशिश मत करो। – Olaf

उत्तर

7

विंडोज़ पर, एक स्मृति आवंटन (प्रतिबद्ध) सफल होगा यदि इसे वापस करने के लिए पर्याप्त पेजिंग फ़ाइल स्थान है। पेजिंग फ़ाइल में उपलब्ध स्थान की मात्रा स्मृति को आरक्षित करने और जारी करने वाली अन्य प्रक्रियाओं के कार्यों के कारण बदल सकती है।

विंडोज़ पर, मॉलोक हेपअलोक के चारों ओर एक पतला आवरण है, जो वर्चुअलअलोक पर बनाया गया है।

वर्चुअलअलोक आपको स्मृति को आरक्षित और/या प्रतिबद्ध करने की अनुमति देगा।

  • साधन अलग प्रक्रिया के वर्चुअल पता स्थान की एक श्रृंखला की स्थापना का आरक्षण। वर्चुअल पतों की रेंज उपलब्ध होने पर आरक्षण सफल होता है। इसका मतलब यह नहीं है कि स्मृति उपलब्ध है, बस उन पते का उपयोग किसी और चीज़ के लिए नहीं किया जाएगा।

  • पर काम करना मतलब है पेजिंग फ़ाइल में अंतर को अलग करना। एक प्रतिबद्धता सफल होती है यदि पेजिंग फ़ाइल में प्रतिबद्धता को वापस करने के लिए पर्याप्त खाली स्थान है।

आरक्षित लेकिन अभी तक प्रतिबद्ध स्मृति तक पहुंच एक त्रुटि है और शायद दुर्घटनाग्रस्त हो जाएगी।

प्रतिबद्ध स्मृति तक पहुंच पृष्ठ त्रुटियों को ट्रिगर कर सकती है, जो सिस्टम उन पृष्ठों को वास्तविक रैम में मैप करके संभालती है। यदि आवश्यक हो, तो कुछ रैम को पेजिंग फ़ाइल में कॉपी किया जाएगा (जो कि पर्याप्त स्थान होने की गारंटी है क्योंकि प्रतिबद्धता सफल हुई), और उसके बाद उस रैम को उस पृष्ठ के लिए फिर से तैयार किया गया है जो मूल रूप से पेज गलती को ट्रिगर करता है। इस प्रकार प्रतिबद्ध स्मृति तक पहुंच हमेशा सफल होती है।

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

चूंकि मॉलोक हीपअलोक पर केवल एक पतला आवरण है, पिछला अनुच्छेद मॉलोक पर भी लागू होता है।

इसमें एक अतिरिक्त शिकन है कि हेपअलोक बड़े आवंटन को अलग से संभालता है। मुझे यकीन नहीं है कि ये प्रारंभिक आरक्षण से आते हैं या यदि वे अलग-अलग ब्लॉक हैं।

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

इसके अलावा, सिस्टम कथित मांग, नीति और उपलब्ध डिस्क स्थान के आधार पर पेजिंग फ़ाइल के आकार को समायोजित कर सकता है। तो यदि आप एक बार सीमा को हिट करते हैं, लेकिन बाद में पुनः प्रयास करें, तो आप पाएंगे कि सीमा अधिक है।

1

के बाद से ऑपरेटिंग सिस्टम उपयोगकर्ता के लिए उपलब्ध स्मृति का प्रबंधन करने की जिम्मेदारी है , आप उस क्षण में उपलब्ध स्मृति की मात्रा के रैखिक व्यवहार की अपेक्षा नहीं कर सकते जब आप अपने मॉलोक को कॉल करते हैं। दो चरणों के बीच, ओएस हार्ड डिस्क या रैम मेमोरी के किसी अन्य क्षेत्र में स्वैप करने की मात्रा को मुक्त कर सकता है, भले ही आप स्पष्ट रूप से कॉल न करें। यही कारण है कि आप विफलता की उम्मीद करते हैं लेकिन मॉलोक सफलता के साथ निष्पादित किया जाता है।

संक्षिप्त उत्तर: ओएस उपलब्ध स्मृति को मुक्त कर सकता है भले ही आप इसे कॉल न करें।

+2

नहीं, ओएस वास्तव में एक प्रक्रिया द्वारा उपयोग की जाने वाली "मुक्त" (यानी पुनः प्राप्त "स्मृति नहीं करेगा।लेकिन यह आशावादी दृष्टिकोण पर सिस्टम में वास्तव में उपलब्ध होने की तुलना में अधिक स्मृति को आरक्षित कर सकता है, प्रक्रिया को वास्तव में सभी पृष्ठों की आवश्यकता नहीं होगी। यहां तक ​​कि 'कॉलोक' भी मदद नहीं कर सकता है (उदा। लिखने पर प्रतिलिपि बनाएँ)। आधुनिक ओएस काफी स्मार्ट हैं। – Olaf

+0

मुझे लगता है कि मैं थोड़ा असहमत हूं। मैं एक असली मुफ़्त नहीं कह रहा था, मैंने कुछ मुफ्त में कहा, उदाहरण के लिए एक स्वैप कर रहा था। यह एक मुफ़्त नहीं है लेकिन समान है। –

+0

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

3

जब आप malloc पर कॉल करते हैं, तो वास्तव में क्या होता है कि आप वर्चुअल मेमोरी आवंटित कर रहे हैं। एक बार जब आप उस स्मृति तक पहुंचने का प्रयास करते हैं, तो यह वास्तविक, भौतिक स्मृति आवंटित करने के लिए ओएस (कर्नेल) को ट्रिगर करता है और उस वर्चुअल एड्रेस (आपके पॉइंटर) पर वास्तविक मेमोरी पता मैप करता है।
अधिकांश, यदि नहीं, तो अधिकांश सिस्टम स्मृति के बावजूद एक पॉइंटर लौटते हैं, भले ही आप malloc पर कॉल न करें। या कम से कम: इसके आवश्यक रूप में उपलब्ध नहीं है (यानी स्मृति के एक संगत ब्लॉक के रूप में)।

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

अब, किसी विशेष बिंदु पर आप वास्तव में उस स्मृति को लिख रहे हैं। आपको समझने की आवश्यकता है कि, जब तक कि आप इस आवंटित वर्चुअल मेमोरी तक नहीं पहुंच जाते, तब तक इसे भौतिक स्मृति में मैप करने की आवश्यकता नहीं होती है। लिनक्स की तरह कुछ सिस्टम भौतिक स्मृति आवंटित नहीं करेंगे जबतक कि आप वास्तव में malloc 'एड ब्लॉक तक पहुंच नहीं पाते। जब ऐसा होता है, तो यह कर्नेल को वास्तव में अंदर जाने और भौतिक स्मृति आवंटित करने के लिए ट्रिगर करता है। वह भौतिक स्मृति पता आभासी पते पर मैप किए जाने से है। इसे आशावादी आवंटन कहा जाता है।

क्योंकि अधिकांश (यदि नहीं सभी) आधुनिक प्रणाली आशावादी आवंटन का उपयोग करती है, तो वे उस समय वास्तव में उपलब्ध होने की तुलना में अधिक स्मृति आवंटित करने की अनुमति दे सकते हैं। क्या मायने रखता है कि यह स्मृति तब तक उपलब्ध है जब प्रक्रिया वास्तव में इसका उपयोग शुरू कर रही है। कुछ आप नहीं करते हैं।

जब आप free पर malloc 'एड मेमोरी जिसे आपने कभी भी उपयोग नहीं किया है, जिसे आप वास्तव में रिलीज़ करते हैं, वर्चुअल मेमोरी है। भौतिक स्मृति छूटी रहती है। यदि आपने हेप मेमोरी को लिखा है, और फिर free पर कॉल करें, तो संभवतः स्मृति की ब्लॉक हमेशा सिस्टम पर वापस नहीं आती है (यह वास्तव में free का काम नहीं है)। अगली बार जब आप malloc पर कॉल करते हैं, तो यह बहुत संभव है कि नई आवंटित मेमोरी ब्लॉक से ली जाएगी जो आप free 'डी। लेकिन ये कार्यान्वयन विवरण हैं जो हमें बहुत दूर ले जाएंगे।

malloc स्मृति का एक हिस्सा में एक ध्वज रोपण इतना है कि और कुछ नहीं, किसी भी तरह से आकार या रूप में है जैसा नहीं है:

इस तरह के मामलों में, मैं वास्तविक दुनिया स्थितियों का उपयोग कर मूर्खतापूर्ण उपमा का उपयोग करना चाहते उस स्मृति तक पहुंचने की अनुमति है। यह एक रेस्तरां में आरक्षण बुकिंग की तरह है। रेस्टोरेंट अक्सर अधिक किताब देखते हैं, क्योंकि वे उम्मीद करते हैं कि लोग न दिखें, या रद्द करें। 99.99% समय, जब आप रेस्तरां में पहुंचते हैं, तो आपके लिए एक टेबल उपलब्ध होगी। (रेस्तरां ने मेजबान को आवंटित आवंटित किया)।

यदि आप प्रदर्शित नहीं करते हैं (यानी आप स्मृति तक नहीं पहुंचते हैं), तो तालिका अन्य लोगों के उपयोग के लिए उपलब्ध है। यदि आप पहुंचे, तो बैठे और अपना रात्रिभोज खाया (स्मृति में लिखें), आप free बिल का भुगतान करके और छोड़कर तालिका में खाते हैं। मेज के साथ रेस्तरां मालिक क्या करता है आपकी चिंता नहीं है। उनके पास किसी और के लिए एक उत्कृष्ट आरक्षण हो सकता है जो आपके जाने के 10 मिनट बाद पहुंच जाएगा। यदि हां, तो रेस्टोरेंटियों ने दो बार समान संसाधन आवंटित किया, लेकिन इससे समस्याएं उत्पन्न नहीं हुईं क्योंकि संसाधन free 'डी था जब तक इसकी आवश्यकता नहीं थी।

यह विस्तृत सादृश्य, अनिवार्य रूप से, कैसे और क्यों आशावादी आवंटन कार्य करता है।

+1

मुझे इस बारे में पता है, और यही कारण है कि मैं उलझन में हूं। चूंकि 'malloc' को कॉल करने से वास्तव में भौतिक स्मृति को आरक्षित नहीं किया जाता है, केवल प्रक्रिया के वर्चुअल एड्रेस स्पेस का एक हिस्सा होता है, इसलिए यह पता स्थान मेरी प्रक्रिया में 100% उपलब्ध होना चाहिए। फिर आभासी पता स्थान का एक नया हिस्सा अचानक "पाया" कैसे है? – baruch

+0

@baruch: पता स्थान 100% उपलब्ध नहीं होना चाहिए। इसे आलसी आवंटित किया जा सकता है और भौतिक स्मृति में भी मैप किया जा सकता है। यदि आप वर्चुअल मेमोरी का उपयोग करते हैं, लेकिन पर्याप्त _actual_ मेमोरी उपलब्ध नहीं है, तो ओओएम हत्यारा कुछ (संभवतः आपकी) प्रक्रिया (ओओएम = मेमोरी से बाहर) की यात्रा का भुगतान करेगा। आशावादी आवंटन –

+0

का उपयोग करने का नकारात्मक पक्ष यह है कि आपकी वर्चुअल मेमोरी वास्तव में भौतिक मेमोरी पर मैप की गई है और यह एक ऐसी चीज है जो भविष्यवाणी करने में कठोर है, या यहां तक ​​कि सटीक रूप से समझाती है, क्योंकि आप विंडोज मशीन पर हैं। कर्नेल पृष्ठों को स्वैप कर सकता है, या बस भौतिक पता बदल सकता है क्योंकि यह कुछ प्रक्रिया के लिए उपलब्ध स्मृति का एक संगत ब्लॉक बनाने की कोशिश कर रहा है। इन चीजों को कार्यान्वित परिभाषित किया गया है ('मॉलोक' कार्यान्वयन विवरण), और प्लेटफ़ॉर्म विशिष्ट (यानी कर्नेल के मेमोरी प्रबंधन मॉडल) –

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