2009-11-05 14 views
9

मुझे अपने कार्यक्रम में स्मृति विखंडन में परेशानी हो रही है और थोड़ी देर के बाद बहुत बड़ी मेमोरी ब्लॉक आवंटित करने में सक्षम नहीं है। मैंने इस मंच पर संबंधित पोस्ट पढ़ी हैं - मुख्य रूप से this एक। और मेरे पास अभी भी कुछ प्रश्न हैं।हीप विखंडन और विंडोज़ मेमोरी मैनेजर

मैं स्मृति की तस्वीर प्राप्त करने के लिए मेमोरी स्पेस profiler का उपयोग कर रहा हूं। मैंने एक 1 लाइन प्रोग्राम लिखा जिसमें सीन >> var शामिल है; और स्मृति की एक तस्वीर ली:

alt text http://img22.imageshack.us/img22/6808/memoryk.gif शीर्ष चाप पर जहां हरा खाली स्थान इंगित करता है, पीला आवंटित, लाल प्रतिबद्ध होता है। मेरा सवाल यह है कि दाईं ओर आवंटित स्मृति क्या है? क्या यह मुख्य धागे के लिए ढेर है? यह स्मृति मुक्त नहीं होने जा रही है और यह मुझे आवश्यक स्मृति की विभाजित करता है। इस सरल 1 लाइन प्रोग्राम में विभाजन उतना बुरा नहीं है। मेरे वास्तविक कार्यक्रम में पता स्थान के बीच में आवंटित अधिक सामान है, और मुझे नहीं पता कि यह कहां से आ रहा है। मैं अभी तक उस स्मृति को आवंटित नहीं कर रहा हूं।

  1. मैं इसे हल करने का प्रयास कैसे कर सकता हूं? मैं nedmalloc या dlmalloc जैसे कुछ स्विच करने के बारे में सोच रहा था। हालांकि यह केवल उन वस्तुओं पर लागू होगा जो मैं स्पष्ट रूप से आवंटित करता हूं, जबकि चित्र में दिखाया गया विभाजन दूर नहीं जाएगा? या सीआरटी आवंटन को किसी अन्य मेमोरी मैनेजर के साथ बदलने का कोई तरीका है?

  2. ऑब्जेक्ट्स बोलना, क्या सी ++ के लिए नेडमॉलोक के लिए कोई रैपर हैं इसलिए मैं ऑब्जेक्ट आवंटित करने के लिए नया उपयोग कर सकता हूं?

धन्यवाद।

+1

माइक्रोसॉफ्ट सुरक्षा अनिवार्यताएं सोचती हैं कि मूल प्रश्न में जुड़े "प्रोफाइलर" एप्लिकेशन में Win32.Bisar! Rts trojan शामिल है। –

उत्तर

12

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

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

जो टुकड़ा आप देख सकते हैं वह चिंता करने के लिए कुछ भी नहीं है, यह आपके पता स्थान से कुछ भी कम नहीं करता है। जैसा कि आपने ध्यान दिया है, डीएलएस हैं, हालांकि, पता स्थान में अन्य बिंदुओं पर लोड होता है। आईआईआरसी shlwapi.dll एक विशेष रूप से खराब उदाहरण है, जो 0x2000000 (फिर से आईआईआरसी) पर लोड हो रहा है जो अक्सर उपलब्ध पता स्थान के एक बड़े हिस्से को दो छोटे टुकड़ों में विभाजित करता है। इसके साथ समस्या यह है कि एक बार डीएलएल लोड होने के बाद, आप इस आवंटित स्थान को स्थानांतरित करने के लिए कुछ भी नहीं कर सकते हैं।

यदि आप डीएलएल (या तो सीधे या किसी अन्य डीएलएल के माध्यम से) के खिलाफ लिंक करते हैं, तो ऐसा कुछ भी नहीं है जो आप कर सकते हैं। यदि आप LoadLibrary का उपयोग करते हैं तो आप स्नीकी प्राप्त कर सकते हैं और इसे सुरक्षित स्थान आरक्षित कर सकते हैं, इसे स्थानांतरित करने के लिए मजबूर कर सकते हैं - अक्सर उस स्थान की जगह में कहीं बेहतर है - आरक्षित स्मृति को जारी करने से पहले। हालांकि यह हमेशा काम नहीं करता है।

हुड के अंतर्गत, पता अंतरिक्ष मॉनिटर VirtualQueryEx का उपयोग करता है प्रक्रिया के पता स्थान की जांच करने लेकिन वहाँ जो अन्य उपकरणों का उपयोग psapi लायब्रेरी से कोई अन्य कॉल (जैसे Process Explorer) है जो आप दिखा सकते हैं जो (DLLs सहित) फ़ाइलें मैप की जाती हैं है पता स्थान के किन हिस्सों में।

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

इसी तरह आप मेमोरी मैप की गई फ़ाइलों या Address Windowing Extensions का उपयोग करके संभवतः एक पेजिंग रणनीति का उपयोग कर सकते हैं।

+0

हे और एक महान उपकरण के लिए धन्यवाद, और प्रक्रिया एक्सप्लोरर की विशेषता को इंगित करता है। – Budric

+0

@ चार्ल्स बेली: फिर स्थिर लिंकिंग - डीएलएल को पुन: स्थापित नहीं किया जा सका? – rpg

+0

हां, आप डीएलएल को रीबेज कर सकते हैं, और यह * पता स्थान विखंडन और लोड समय को अनुकूलित करने में मदद कर सकता है, हालांकि ... आमतौर पर आपको केवल डीएलएल के साथ ऐसा करना चाहिए और यदि आप बहुत अधिक माइक्रो-ऑप्टिमाइज़ेशन करते हैं तो आप समाप्त होते हैं डीएलएल का एक सेट जो समय पर एक विशेष exe में अच्छी तरह से काम करता है, लेकिन किसी भी अन्य exe के लिए एक अनुकूलित लोडिंग रणनीति इतनी अच्छी नहीं है। यदि आपके डीएलएल फिर से निर्मित और आकार बदलते हैं तो आपको प्रक्रिया को फिर से जाना होगा। तो यह कुछ हद तक काम कर सकता है, लेकिन अगर आपको इसका सहारा लेना है तो आप एक उच्च रखरखाव दुष्चक्र में समाप्त हो सकते हैं। –

1

क्या यह निष्पादन योग्य हो सकता है? इसे कहीं पता स्थान में लोड किया जाना चाहिए ....

2 के रूप में वैश्विक नए ओवरराइड करने और कार्यों को हटाने के लिए यह बहुत आसान है ... बस उन्हें परिभाषित करें।

2

मुझे लगता है कि आप अक्सर अलग-अलग आकारों की वस्तुओं को आवंटित और हटा रहे हैं और यही कारण है कि आपकी स्मृति विखंडन के मुद्दों का कारण बनता है?

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

के रूप में (2), मुझे nedmalloc के चारों ओर एक रैपर के बारे में पता नहीं है (स्पष्ट रूप से, मैं nedmalloc से बहुत परिचित नहीं हूं) लेकिन आप अपने स्वयं के रैपर बहुत आसानी से बना सकते हैं क्योंकि आप या तो कक्षा-विशिष्ट ऑपरेटरों को बना सकते हैं नए ऑपरेटरों को हटाएं और हटाएं या यहां तक ​​कि अधिभार/प्रतिस्थापित करें और हटाएं। मैं उत्तरार्द्ध का बड़ा प्रशंसक नहीं हूं लेकिन यदि आपका आवंटन "हॉटस्पॉट" में कुछ हद तक कक्षाएं होती हैं, तो आमतौर पर उन्हें अपने स्वयं के, वर्ग-विशिष्ट ऑपरेटरों के साथ दोबारा हटाने और हटाने के लिए बहुत आसान होता है।

यह कहा गया है कि, nedmalloc मानक malloc/free के लिए प्रतिस्थापन के रूप में खुद को बिल करता है और कम से कम एमएस कंपाइलर्स के साथ, मुझे लगता है कि सी ++ रनटाइम लाइब्रेरी नए/आगे malloc/free को हटा देगी, इसलिए यह शायद एक मामला हो सकता है nedmalloc के साथ अपने निष्पादन योग्य बनाने के लिए।

1

यह पता लगाने का सबसे अच्छा तरीका है कि आपके प्रोग्राम में स्मृति आवंटित की जाती है, यह एक डीबगर का उपयोग करना है। प्रत्येक लोड किए गए डीएलएल और निष्पादन योग्य स्वयं के लिए आवंटन होते हैं, और उनमें से सभी खंड वर्चुअल मेमोरी हैं। इसके अतिरिक्त, सी/सी ++ पुस्तकालयों और विंडोज एपीआई का उपयोग आपके आवेदन में एक ढेर बनने का कारण बन जाएगा, जो कम से कम वर्चुअल मेमोरी का एक हिस्सा आरक्षित करेगा।

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

यदि आप विंडबग का उपयोग करते हैं, तो आप देख सकते हैं कि स्मृति के कौन से क्षेत्र उपभोग किए जाते हैं, आरक्षित, आदि। एलएम कमांड आपको सभी डीएलएल और EXE और उनकी सीमा के लोड पते दिखाएगा। ! Vadump कमांड आपको प्रक्रिया और पृष्ठ सुरक्षा द्वारा उपयोग की जाने वाली सभी वर्चुअल मेमोरी दिखाएगा। पृष्ठ सुरक्षा क्या है वहां एक बड़ा संकेत है। उदाहरण के लिए निम्न (आंशिक)! 64-बिट calc.exe प्रक्रिया से vadump में, आप देखेंगे कि पहला क्षेत्र केवल एक्सेस से संरक्षित वर्चुअल मेमोरी की एक श्रृंखला है। (अन्य चीजों के अलावा यह आपको पते 0 पर स्मृति आवंटित करने से रोकता है।) MEM_COMMIT का अर्थ है कि मेमोरी रैम या पेजिंग फ़ाइल द्वारा समर्थित है। PAGE_READWRITE संभवतः ढेर स्मृति, या एक लोड मॉड्यूल के डेटा खंड है। PAGE_READEXECUTE आमतौर पर कोड लोड होता है और यह एलएम द्वारा उत्पादित सूची में दिखाई देगा। MEM_RESERVE का मतलब है कुछ स्मृति का एक क्षेत्र आरक्षण VirtualAlloc का आह्वान किया है, लेकिन यह बहुत आगे वर्चुअल मेमोरी प्रबंधक द्वारा मैप नहीं है कि, और ...

0:004> !vadump 
BaseAddress:  0000000000000000 
RegionSize:  0000000000010000 
State:    00010000 MEM_FREE 
Protect:   00000001 PAGE_NOACCESS 

BaseAddress:  0000000000010000 
RegionSize:  0000000000010000 
State:    00001000 MEM_COMMIT 
Protect:   00000004 PAGE_READWRITE 
Type:    00040000 MEM_MAPPED 

BaseAddress:  0000000000020000 
RegionSize:  0000000000003000 
State:    00001000 MEM_COMMIT 
Protect:   00000002 PAGE_READONLY 
Type:    00040000 MEM_MAPPED 

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

यदि आप वास्तव में केवल ढेर के बारे में परवाह करते हैं, तो देखो! ढेर।

+0

धन्यवाद, मैं विंडबग का प्रयास करूंगा। – Budric

2

स्मृति विखंडन को कम करने के लिए, आप Windows Low-Fragmentation Heap का लाभ उठा सकते हैं। हमने इसे अपने उत्पाद में अच्छे प्रभाव के लिए उपयोग किया है और ऐसा करने के बाद से लगभग कई स्मृति संबंधी समस्याएं नहीं हैं।

+0

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

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