2011-11-17 19 views
8

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

अतीत में, मैं आसानी से उपयोगकर्ता को समझा सकता हूं कि यदि स्मृति 1.6 से 1.7 जीबी मेमोरी उपयोग तक पहुंच गई, तो यह 'स्मृति से बाहर' या वास्तव में 'स्मृति से बाहर' स्थिति के करीब थी, और उन्हें चाहिए उनकी याददाश्त को कम करने या 64-बिट संस्करण में जाने के लिए।

पिछले साल मैंने देखा कि अक्सर एप्लिकेशन केवल स्मृति से बाहर होने से पहले लगभग 1 जीबी का उपयोग करता है। कुछ जांच के बाद ऐसा लगता था कि इस समस्या का कारण स्मृति विखंडन है। मैंने अपने आवेदन के मेमोरी उपयोग को देखने के लिए वीएमएमएपी (एक SysInternals उपयोगिता) का उपयोग किया और इस तरह कुछ देखा: Address Space Fragmentation

नारंगी क्षेत्रों को मेरे आवेदन द्वारा आवंटित स्मृति है। बैंगनी क्षेत्र निष्पादन योग्य कोड हैं।

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

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

प्रश्न हैं:

  • मैं स्थान जहां DLL की स्मृति में लोड किए गए हैं, स्पष्ट रूप से सभी DLL के ग्राहक के कंप्यूटर पर पर rebase का उपयोग किए बिना कैसे प्रभावित कर सकते हैं, या सभी DLL का स्पष्ट रूप से लोड किए बिना।
  • क्या आपके स्वयं के एप्लिकेशन मेनिफेस्ट फ़ाइल में डीएलएल के लोड पते निर्दिष्ट करने का कोई तरीका है?
  • या क्या डीएलएल के आसपास स्कैटर नहीं करने के लिए विंडोज़ (मैनिफेस्ट फ़ाइल के माध्यम से) को बताने का कोई तरीका है (मुझे लगता है कि इस स्कैटरिंग को एएसएलआर कहा जाता है)।

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

मेरा आवेदन एक मिश्रित मोड (प्रबंधित + अप्रबंधित) एप्लिकेशन है, हालांकि एप्लिकेशन का मुख्य हिस्सा अप्रबंधित है।

कोई भी सुझाव?

+0

क्या यह ऐसा कुछ है जो आपकी मदद कर सकता है? http://msdn.microsoft.com/en-us/library/f7f5138s.aspx – detunized

+1

mmm, क्या आपको वास्तव में एक ही समय में उस स्मृति की आवश्यकता है? प्रोसेस मॉनिटर वर्चुअल मेमोरी में अपने लॉग स्टोर करता है और आवश्यकता होने पर केवल प्रक्रिया की मेमोरी एड्रेस स्पेस में डेटा लाता है, कोड के लिए http://blogs.msdn.com/b/oldnewthing/archive/2004/08/10/211890.aspx जांचें उदाहरण –

+1

मुझे यकीन नहीं है कि उत्तर छोड़ने वाले सभी लोग एएसएलआर की विधियों को समझते हैं: http://en.wikipedia.org/wiki/ASLR –

उत्तर

5

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

आप कहते हैं कि आपका अधिकांश डेटा "एसटीएल-आधारित" है, लेकिन यदि उदाहरण के लिए आप एक विशाल std::vector आवंटित करते हैं तो आपको एक संगत स्मृति ब्लॉक की आवश्यकता होगी।

AFAIK इसके लोड पर डीएलएल के पसंदीदा मैपिंग पते को निर्दिष्ट करने का कोई तरीका नहीं है। ताकि केवल दो विकल्प हों: या तो इसे रीबेज करें (डीएलएल फ़ाइल), या डीएलएल को स्वयं लोड करना लागू करें (जो पाठ्यक्रम की तुच्छ नहीं है)।

आमतौर पर आपको मानक विंडोज एपीआई डीएलएल को पुन: पेश करने की आवश्यकता नहीं होती है, वे आपके पता स्थान पर बहुत कसकर लोड होते हैं। फ्रैगमेंटेशन कुछ तृतीय पक्ष डीएलएल (जैसे कि विंडोज हुक, एंटीवायरस इंजेक्शन और इत्यादि) से आ सकता है

3

आप इसे एक मैनिफेस्ट के साथ नहीं कर सकते हैं, यह लिंकर/BASE विकल्प द्वारा किया जाना चाहिए। आईडीई में लिंकर + उन्नत + बेस पता। सबसे लचीला तरीका/BASE का उपयोग करना है: @ फ़ाइल नाम, कुंजी वाक्यविन्यास ताकि लिंकर टेक्स्ट फ़ाइल से मूल पता पढ़ सके।

टेक्स्ट फ़ाइल भरने का सबसे अच्छा तरीका डीबग + विंडोज + मॉड्यूल विंडो से है। डीबगर में लोड किए गए अपने प्रोग्राम का रिलीज बिल्ड प्राप्त करें और पूरे शेबांग को लोड करें। डीबग + सभी को तोड़ें, खिड़की लाएं और इसे टेक्स्ट फ़ाइल में कॉपी करें। पता कॉलम से लोड पते की गणना, आवश्यक प्रारूप से मेल खाने के लिए इसे संपादित करें। डीएलएल के बीच पर्याप्त जगह छोड़ दें ताकि आपको लगातार टेक्स्ट फ़ाइल को ट्विक नहीं करना पड़े।

+0

बेशक यह एक सामान्य प्रणाली पर पाए गए सभी हुक डीएलएल के साथ बिल्कुल मदद नहीं करता है । ग्राफिक ड्राइवर। एंटी वायरस माउस चालक आदि –

+0

हम्म, नहीं, यहां तक ​​कि उनको rebase.exe उपकरण के साथ भी हैक किया जा सकता है। इतना यकीन नहीं है कि मैं ऐसा करने की सिफारिश करता हूं, समय बर्बाद न करें जबतक कि आप अपनी मशीन को अपने उत्पाद के साथ शिपिंग करने की योजना नहीं बनाते। –

1

यदि आप प्रश्न में पुस्तकालयों को लोड करने से पहले अपने कुछ कोड निष्पादित करने में सक्षम हैं, तो आप आवंटित करने के लिए समय से पहले पता स्थान का एक बड़ा बड़ा हिस्सा आरक्षित कर सकते हैं।

अन्यथा, आपको यह निर्धारित करने के लिए जिम्मेदार डीएलएल की पहचान करने की आवश्यकता है, यह निर्धारित करने के लिए कि उन्हें क्यों लोड किया जा रहा है। उदाहरण के लिए, क्या वे .NET, भाषा की रनटाइम लाइब्रेरी, अपना स्वयं का कोड, या तृतीय पक्ष लाइब्रेरी का हिस्सा हैं जिनका आप उपयोग कर रहे हैं?

अपने स्वयं के कोड के लिए सबसे समझदार समाधान शायद गतिशील लिंकिंग के बजाय स्थिर का उपयोग करना है। भाषा रनटाइम के लिए यह भी संभव होना चाहिए और तीसरे पक्ष के पुस्तकालयों के लिए संभव हो सकता है।

तीसरे पक्ष के पुस्तकालयों के लिए, आप स्पष्ट लोडिंग के लिए अंतर्निहित लोडिंग का उपयोग करने से बदल सकते हैं, ताकि लोडिंग स्थान के अपने हिस्से को आरक्षित करने के बाद ही लोड हो।

मुझे नहीं पता कि .NET पुस्तकालयों के बारे में आप कुछ भी कर सकते हैं; लेकिन चूंकि आपका अधिकांश कोड अप्रबंधित है, इसलिए .NET से छुटकारा पाने के लिए प्रबंधित घटकों को खत्म करना संभव हो सकता है। या शायद आप .NET भागों को एक अलग प्रक्रिया में विभाजित कर सकते हैं।

+0

... लेकिन यह एक बड़े संगत स्मृति ब्लॉक के लिए आवश्यकता को खत्म करने के लिए आवश्यक कार्यक्रम को दोबारा करने के लिए और अधिक समझदार होगा। –