2011-03-24 6 views
7

मैं एमएसवीसी 9.0 के साथ विंडोज 7 पर सी ++ का उपयोग कर रहा हूं, और एमएसवीसी 9.0 के साथ विंडोज एक्सपी एसपी 3 पर परीक्षण और पुन: उत्पन्न करने में भी सक्षम हूं।हटाई गई मेमोरी को पुन: उपयोग करने में असमर्थ क्यों है

यदि मैं उन्हें हटा देता हूं तो 1 जीबी 0.5 एमबी आकार की वस्तुओं को आवंटित करता हूं, सब कुछ ठीक है और अपेक्षित व्यवहार करता है। हालांकि अगर मैं उन्हें हटा देता हूं तो 1 जीबी 0.25 एमबी आकार की वस्तुओं को आवंटित करता हूं, तो स्मृति आरक्षित होती है (Address Space Monitor में पीला) और तब से केवल 0.25 एमबी से छोटे आवंटन के लिए उपयोग किया जा सकता है।

यह सरल कोड आपको दोनों परिदृश्यों का परीक्षण करके बताएगा कि कौन सी संरचना टाइप की गई है। इसके बाद structs आवंटित और हटा दिए जाने के बाद यह 1 जीबी 1 एमबी चार बफर आवंटित करेगा यह देखने के लिए कि क्या चार बफर एक बार कब्जे वाले सूत्रों का उपयोग करेंगे।

struct HalfMegStruct 
{ 
    HalfMegStruct():m_Next(0){} 

    /* return the number of objects needed to allocate one gig */ 
    static int getIterations(){ return 2048; } 

    int m_Data[131071]; 
    HalfMegStruct* m_Next; 
}; 

struct QuarterMegStruct 
{ 
    QuarterMegStruct():m_Next(0){} 

    /* return the number of objects needed to allocate one gig */ 
    static int getIterations(){ return 4096; } 

    int m_Data[65535]; 
    QuarterMegStruct* m_Next; 
}; 

// which struct to use 
typedef QuarterMegStruct UseType; 

int main() 
{ 
    UseType* first = new UseType; 
    UseType* current = first; 

    for (int i = 0; i < UseType::getIterations(); ++i) 
     current = current->m_Next = new UseType; 

    while (first->m_Next) 
    { 
     UseType* temp = first->m_Next; 
     delete first; 
     first = temp; 
    } 

    delete first; 

    for (unsigned int i = 0; i < 1024; ++i) 
     // one meg buffer, i'm aware this is a leak but its for illustrative purposes. 
     new char[ 1048576 ]; 

    return 0; 
} 

नीचे आप Address Space Monitor के भीतर से अपने परिणाम देख सकते हैं। मुझे तनाव दें कि इन दो अंतिम परिणामों के बीच एकमात्र अंतर 1 जीबी मार्कर तक आवंटित किए गए structs का आकार है।

Quarter Meg Half Meg

यह मेरे लिए काफी एक गंभीर समस्या है, और एक है कि कई लोगों से पीड़ित हो सकता है और यहां तक ​​कि यह पता नहीं की तरह लगता है।

  • तो क्या यह डिज़ाइन द्वारा है या इसे एक बग माना जाना चाहिए?
  • क्या मैं छोटी आवंटित वस्तुओं को वास्तव में बड़े आवंटन के उपयोग के लिए मुक्त कर सकता हूं?
  • और जिज्ञासा से अधिक, क्या मैक या लिनक्स मशीन एक ही समस्या से पीड़ित है?
+1

आकार सीमा के अलावा, स्मृति विखंडन की तरह बदबू आ रही है। –

+0

यह करता है, हालांकि स्मृति विखंडन तब होता है जब आवंटित वस्तुओं के बीच बर्बाद जगह होती है। उपर्युक्त कोड में, सब कुछ हटा दिया गया है, इसलिए स्मृति विखंडन मुद्दा नहीं हो सकता है। – 0xC0DEFACE

+0

आप कहते हैं कि आरक्षित मेमोरी केवल 0.25 एमबी से कम आवंटित वस्तुओं के लिए उपयोग की जा सकती है। इसलिए, जब आप कई बड़ी ऑब्जेक्ट्स आवंटित करते हैं, तो क्या आपको स्मृति का अपवाद मिलता है जबकि यह स्मृति अभी भी आरक्षित है?मैं यह पूछता हूं क्योंकि, मैक ओएस पर, ऑपरेटिंग सिस्टम अप्रयुक्त मेमोरी को तेजी से पुनर्वितरण के लिए आरक्षित रखेगा, जब तक कि किसी अन्य प्रक्रिया को वास्तव में उस स्मृति की आवश्यकता न हो। –

उत्तर

9

मैं सकारात्मक स्थिति नहीं बता सकता कि यह मामला है, लेकिन यह स्मृति विखंडन (इसके कई रूपों में से एक में) जैसा दिखता है। ऑलोकेटर (मॉलोक) तेजी से आवंटन को सक्षम करने के लिए विभिन्न आकारों की बाल्टी रख सकता है, स्मृति को छोड़ने के बाद, इसे सीधे ओएस पर वापस देने की बजाय यह बाल्टी रखता है ताकि बाद में उसी आकार के आवंटन को संसाधित किया जा सके। एक ही स्मृति यदि ऐसा है, तो स्मृति एक ही आकार के आगे आवंटन के लिए उपलब्ध होगी।

अनुकूलन इस प्रकार का आमतौर पर, बड़ा वस्तुओं के लिए अक्षम के रूप में यह आवश्यकता है स्मृति भी उपयोग में नहीं है, तो आरक्षित है। यदि दहलीज आपके दो आकारों के बीच कहीं है, तो यह व्यवहार की व्याख्या करेगी।

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

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

मैं खिड़कियों के लिए नहीं आम तौर पर कोड करते हैं, और मैं भी विंडोज 7 नहीं है, इसलिए मैं सकारात्मक राज्य नहीं कर सकता कि यह मामला है, लेकिन यह यह कैसा दिखाई देता है।

+0

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

2

मैं विंडोज 7 के तहत ग्राम ++ 4.4.0 के साथ एक ही व्यवहार की पुष्टि कर सकते हैं, तो यह संकलक में नहीं है। वास्तव में, प्रोग्राम विफल रहता है जब getIterations()3590 या उससे अधिक लौटाता है - क्या आपको वही कटऑफ मिलता है? यह विंडोज सिस्टम मेमोरी आवंटन में एक बग की तरह दिखता है। जानकार आत्माओं के लिए स्मृति विखंडन के बारे में बात करना बहुत अच्छा है, लेकिन सबकुछ यहां हटा दिया गया है, इसलिए मनाया गया व्यवहार निश्चित रूप से नहीं होना चाहिए।

+0

विभिन्न चीजों को स्मृति विखंडन कहा जाता है। एक भयानक स्मृति आवंटक में जो एक ही ढेर से सभी अनुरोधों को उत्पन्न करता है, स्मृति विखंडन स्मृति में छेद को संदर्भित करता है जिसे आवंटित नहीं किया जा सकता क्योंकि वे अनुरोध के लिए बहुत छोटे हैं। अन्य कार्यान्वयन अलग-अलग आकार के ऑब्जेक्ट्स के लिए अलग-अलग * ढेर * रखेंगे, * विखंडन * को कम करने के प्रयास में, ताकि एक ही आकार के साथ नए/हटाए गए/नए/हटाए/नए के अनुक्रमों को स्मृति को खंडित न करने की गारंटी दी जा सके। मेमोरी उपलब्ध नहीं है क्योंकि इसे एक अलग ढेर में पकड़ा जा रहा है जिसे * विखंडन * (एक अलग तरह का) भी कहा जाता है –

+0

@ डेविड: जैसा मैंने कहा, सबकुछ हटा दिया गया। स्मृति आवंटक को यह पहचानना चाहिए, और आवंटन विफल होने पर मध्यम आकार के ऑब्जेक्ट ढेर को मुक्त करना चाहिए (यदि वास्तव में यह हो रहा है)। क्या आप सहमत नहीं हैं? – TonyK

+1

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

1

अपने कोड का उपयोग करके मैंने आपका परीक्षण किया और एक ही परिणाम मिला। मुझे संदेह है कि इस मामले में डेविड रोड्रिग्ज सही है।

मैंने परीक्षण चलाया और आपके जैसा ही परिणाम था। ऐसा लगता है कि यह "बाल्टी" व्यवहार चल रहा है।

मैंने दो अलग-अलग परीक्षणों की भी कोशिश की। 1 एमबी बफर का उपयोग करके 1 जीबी डेटा आवंटित करने के बजाय मैंने उसी तरह आवंटित किया जैसे स्मृति को हटाने के बाद पहली बार आवंटित किया गया था। दूसरे टेस्ट में मैंने अर्ध मेग बफर को साफ किया, फिर क्वाटर मेग बफर आवंटित किया, प्रत्येक के लिए 512 एमबी तक जोड़ा। दोनों परीक्षणों में अंत में एक ही स्मृति परिणाम था, केवल 512 को आरक्षित स्मृति का कोई बड़ा हिस्सा आवंटित नहीं किया गया था।

दाऊद का उल्लेख के रूप में, सबसे अनुप्रयोगों एक ही आकार के आवंटन बना देती हैं। कोई स्पष्ट रूप से देख सकता है कि यह समस्या क्यों हो सकती है।

शायद यह का हल है कि अगर आप इस तरह से कई छोटी वस्तुओं का आवंटन कर रहे हैं आप स्मृति की एक बड़ी ब्लॉक का आवंटन और यह अपने आप का प्रबंधन करने के लिए बेहतर होगा। फिर जब आप बड़े ब्लॉक को मुक्त कर लेंगे।

0

यह लो-फ्रैगमेंटेशन हीप का दुष्प्रभाव है।

http://msdn.microsoft.com/en-us/library/aa366750(v=vs.85).aspx

आप को देखने के लिए कि अगर मदद करता है उसे अक्षम करने का प्रयास करना चाहिए। GetProcessHeap और सीआरटी ढेर (और आपके द्वारा बनाए गए किसी भी अन्य ढेर) के खिलाफ चलाएं।

1

मैं इस विषय पर कुछ अधिकारियों के साथ बात की थी (ग्रेग, अगर आप वहाँ बाहर कर रहे हैं, नमस्ते कहने; डी) और पुष्टि कर सकते हैं कि क्या दाऊद कह रहा है मूल रूप से सही है।

ढेर आवंटन ~ 0.25MB वस्तुओं के पहले पास में विकसित होता है, ढेर आरक्षण और स्मृति करने से है। जैसे ही ढीले डिलीट पास में कमी आती है, यह कुछ गति से कम हो जाती है लेकिन आवंटन पास में आरक्षित वर्चुअल एड्रेस रेंज को जरूरी नहीं है। अंतिम आवंटन पास में, 1 एमबी आवंटन उनके आकार के कारण ढेर को छोड़ रहे हैं और इस प्रकार वीए के लिए ढेर के साथ प्रतिस्पर्धा करना शुरू कर देते हैं।

नोट कि ढेर आरक्षित वीए, रखने नहीं यह प्रतिबद्ध है। VirtualAlloc और VirtualFree यदि आप उत्सुक हैं तो अलग-अलग व्याख्या करने में सहायता कर सकते हैं। यह तथ्य आपके द्वारा चलाए गए समस्या को हल नहीं करता है, यह है कि प्रक्रिया virtual address space से बाहर हो गई।

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