2009-04-12 20 views
12

मैंने एक कनवर्टर लिखा है जो openstreetmap xml फ़ाइलों को लेता है और उन्हें एक बाइनरी रनटाइम रेंडरिंग प्रारूप में परिवर्तित करता है जो आमतौर पर मूल आकार का लगभग 10% होता है। इनपुट फ़ाइल आकार आमतौर पर 3 जीबी और बड़े होते हैं। इनपुट फ़ाइलों को एक साथ स्मृति में लोड नहीं किया जाता है, लेकिन अंक और polys के रूप में स्ट्रीम किया जाता है, तो एक बीएसपी उन पर चलाया जाता है और फ़ाइल आउटपुट है। हाल ही में बड़ी फाइलों पर यह स्मृति से बाहर हो जाता है और मर जाता है (प्रश्न में से एक में 14 मिलियन अंक और 1 मिलियन बहुभुज हैं)। आम तौर पर जब यह होता है तो मेरा प्रोग्राम लगभग 1 जीबी से 1.2 जीबी रैम का उपयोग कर रहा है। मैंने वर्चुअल मेमोरी को 2 से 8 जीबी (एक्सपी पर) बढ़ाने की कोशिश की है, लेकिन इस बदलाव से कोई प्रभाव नहीं पड़ा। साथ ही, चूंकि यह कोड ओपन-सोर्स है, इसलिए मैं उपलब्ध राम (हालांकि धीमे) के बावजूद इसे काम करना चाहता हूं, यह विंडोज, लिनक्स और मैक पर चलता है।उच्च स्मृति उपयोग अनुप्रयोग में स्मृति से बाहर निकलने से कैसे बचें? सी/सी ++

स्मृति से बाहर होने से बचने के लिए मैं किस तकनीक का उपयोग कर सकता हूं? छोटे उप-सेट में डेटा को प्रोसेस करना और फिर अंतिम परिणाम विलय करना? हैंडलर की अपनी वर्चुअल मेमोरी प्रकार का उपयोग करना? कोई अन्य विचार?

उत्तर

14

सबसे पहले, 32-बिट सिस्टम पर, आप हमेशा 4 जीबी तक सीमित रहेंगे, चाहे पेजफाइल सेटिंग्स चाहे। (और उनमें से, केवल 2 जीबी विंडोज़ पर आपकी प्रक्रिया के लिए उपलब्ध होगा। लिनक्स पर, आपके पास आमतौर पर लगभग 3 जीबी उपलब्ध होगा)

तो पहला स्पष्ट समाधान 64-बिट ओएस पर स्विच करना है, और अपने संकलन को संकलित करना है 64-बिट के लिए आवेदन। यह आपको उपयोग करने के लिए एक विशाल वर्चुअल मेमोरी स्पेस देता है, और ओएस चीजों को काम करने के लिए जरूरी पेजफाइल के डेटा को और बाहर स्वैप कर देगा।

दूसरा, एक समय में स्मृति के छोटे हिस्से आवंटित करने में मदद मिल सकती है। एक 1 जीबी खंड से मुफ्त मेमोरी के 4 256 एमबी भाग ढूंढना अक्सर आसान होता है।

तीसरा, समस्या को विभाजित करें। पूरे डेटासेट को एक बार में संसाधित न करें, लेकिन एक समय में केवल एक छोटे से हिस्से को लोड करने और संसाधित करने का प्रयास करें।

+0

विंडोज़ के पास 3 जीबी वर्चुअल स्पेस हो सकता है/LARGEADDRESSAWARE –

+0

फ्लैग प्रक्रिया को 4 जीबी * तक उपयोग करने की अनुमति देता है यदि ओएस इसे * प्रदान कर सकता है। आम तौर पर, विंडोज़ अभी भी प्रत्येक प्रक्रिया में केवल 2 जीबी देने के लिए स्थापित है। यह आपको 3 जीबी देने के लिए ड्राइवर अस्थिरता के जोखिम पर भी बदला जा सकता है। पीएई के साथ, आप और भी प्राप्त कर सकते हैं। लेकिन 64-बिट शायद एक बेहतर शर्त है। – jalf

+1

इमो, तीसरा विकल्प सबसे महत्वपूर्ण है। स्मृति पर नियंत्रण देने के अलावा, यह समानांतर प्रसंस्करण के लिए भी अनुमति देता है। – xtofl

4

ऐसा लगता है कि आप पहले से ही XML प्रसंस्करण के लिए SAX आधारित दृष्टिकोण कर रहे हैं (एक्सएमएल लोड करना जब आप एक बार में सभी के बजाय जाते हैं)।

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

आप कभी-कभी अपने एल्गोरिदम में आवश्यक होने पर हार्ड ड्राइव का उपयोग करके स्मृति का विस्तार कर सकते हैं।

यदि आप अपने एल्गोरिदम को विभाजित नहीं कर सकते हैं, तो शायद आपको memory mapped files जैसे कुछ चाहिए।

सबसे खराब स्थिति में यदि आप विंडोज सिस्टम पर हैं तो VirtualAlloc जैसे कुछ का उपयोग करने का प्रयास कर सकते हैं। यदि आप 32-बिट सिस्टम पर हैं तो आप Physical Address Extension (PAE) जैसे कुछ उपयोग करने का प्रयास कर सकते हैं।

आप अपने प्रोग्राम के लिए इनपुट सीमाएं डालने पर विचार कर सकते हैं, और 32-बिट और 64-बिट सिस्टम के लिए अलग-अलग होना चाहिए।

4

क्या आपने यह सुनिश्चित करने के लिए जांच की है कि आप कहीं भी स्मृति को लीक नहीं कर रहे हैं?

चूंकि आपका प्रोग्राम लिनक्स के लिए पोर्टेबल है, इसलिए मैं इसे सुनिश्चित करने के लिए वालग्रिंड के तहत इसे चलाने का सुझाव देता हूं।

+0

हाँ मैंने लीक के लिए चेक किया है, कोई भी नहीं है। – KPexEA

0

ऐसा लगता है जैसे आप बाइनरी वार्तालाप में txt कर रहे हैं तो आपको स्मृति में संपूर्ण डेटा क्यों होना चाहिए?
क्या आप सिर्फ txt (xml) से आदिम नहीं पढ़ सकते हैं, फिर बाइनरीस्ट्रीम में सहेज सकते हैं?

2

मान लें कि आप Windows XP का उपयोग कर रहे हैं, अगर आप केवल अपनी स्मृति सीमा से अधिक हैं और ऊपर दिए गए अनुसार कोड को फिर से काम करने का समय नहीं चाहते हैं, तो आप अपने boot.ini फ़ाइल में/3 जीबी स्विच जोड़ सकते हैं और फिर यह एक अतिरिक्त 1 जीबी मेमोरी पाने के लिए एक लिंकर स्विच सेट करने की बात है।

+0

3 जीबी का उपयोग करना इतना आसान नहीं है। आपको यह सुनिश्चित करना चाहिए कि आपके सभी सूचक अंकगणितीय परिचालन सुरक्षित हैं, या फिर जब आप स्मृति उपयोग उच्च हो जाते हैं तो आप क्रैश हो जाएंगे। अधिक के लिए http://blogs.msdn.com/oldnewthing/archive/2004/08/12/213468.aspx देखें। – eran

3

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

1

आपको यह समझना होगा कि वर्चुअल मेमोरी "रैम" से अलग है जिसमें आप जिस वर्चुअल मेमोरी का उपयोग कर रहे हैं वह कुल राशि है जिसे आपने आरक्षित किया है, जबकि वास्तविक स्मृति (विंडोज़ में इसे वर्किंग सेट कहा जाता है) स्मृति है कि आपने वास्तव में संशोधित या लॉक किया है।

जैसा कि किसी और ने इंगित किया है, 32-बिट विंडोज प्लेटफ़ॉर्म पर वर्चुअल मेमोरी पर सीमा 2 गीगाबाइट्स है जब तक कि आप 3 गीगाबाइट्स के लिए विशेष ध्वज सेट न करें और यह सुनिश्चित कर सकें कि आपके पॉइंटर्स और आपके द्वारा उपयोग किए जाने वाले किसी भी पुस्तकालय हस्ताक्षरित पॉइंटर्स का प्रयोग करें।

तो या तो उपयोगकर्ताओं को 64-बिट करने या अपनी वर्चुअल मेमोरी की निगरानी करने और 32-बिट ऑपरेटिंग सिस्टम द्वारा लगाई गई सीमाओं के भीतर आराम से फिट बैठने के लिए आपके अधिकतम ब्लॉक आकार को कैप करने के लिए मजबूर करना मेरी सलाह होगी।

मैंने विंडोज़ में 32-बिट दीवार में फिसल दिया है, लेकिन लिनक्स में इन सीमाओं के आसपास काम करने के साथ कोई अनुभव नहीं है इसलिए मैंने केवल चीजों के विंडोज पक्ष के बारे में बात की है।

1

32-बिट XP पर आपका अधिकतम प्रोग्राम पता स्थान 2 जीबी है। फिर आपके पास डीएलएल के कारण विखंडन है और ड्राइवर आपके पता स्थान पर लोड हो रहे हैं। अंत में, आपको अपने ढेर के टुकड़े की समस्या है।

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

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

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

लड़का, 64-बिट कंप्यूटिंग नहीं करता है, अन्य विकल्पों की तुलना में बस इतना अच्छा लगता है?

1

आप अंक के लिए स्मृति आवंटित कैसे कर रहे हैं? क्या आप एक समय में बिंदु आवंटित कर रहे हैं (उदा। pt = new point)। फिर बिंदु के आकार के आधार पर, कुछ स्मृति बर्बाद हो सकती है।उदाहरण के लिए विंडोज मेमोरी पर 16 बाइट्स के गुणकों में आवंटित किया गया है, इसलिए यदि आप 1 बाइट आवंटित करने का प्रयास करते हैं, तो भी ओएस वास्तव में 16 बाइट आवंटित करेगा।

यदि ऐसा है, तो स्मृति आवंटक का उपयोग करने से मदद मिल सकती है। आप एसटीएल आवंटक का उपयोग कर त्वरित जांच कर सकते हैं। (पॉइंट क्लास के लिए नए ऑपरेटर को लोड करने के लिए और 'malloc' या डिफ़ॉल्ट नए ऑपरेटर की बजाय स्मृति आवंटित करने के लिए एसटीएल आवंटक का उपयोग करें)।

+0

मैं एक हीप मैनेजर का उपयोग करके पॉइंट्स और पॉली आवंटित कर रहा हूं, इसलिए वे केवल उतना ही स्थान लेते हैं जितना आवश्यक है और लगभग कोई भी सुना नहीं है क्योंकि मेरे ढेर आवंटित (इस मामले में) 1 एमबी भाग और प्रत्येक खंड से अनुरोधों को डोल करता है – KPexEA

+0

एक और कारण 'स्मृति हो सकता है विखंडन '(यानी स्मृति छोटे हिस्सों में उपलब्ध है लेकिन जब आप' 1 एमबी 'मांगते हैं, तो 1 एमबी खंड उपलब्ध होता है। क्या एक्सएमएल पार्सर' हीप मैनेजर 'का उपयोग करता है? एक्सएमएल पार्सर मानक मेमोरी आवंटन और कारण का उपयोग कर रहा है विखंडन? –

0

यदि आप स्मृति-आकार स्वतंत्र होना चाहते हैं, तो आपको आकार-स्वतंत्र एल्गोरिदम की आवश्यकता है। इससे कोई फर्क नहीं पड़ता कि आपकी रैम कितनी आकार है, अगर आपके पास मेमोरी उपयोग नियंत्रण में नहीं है, तो आप सीमा में टक्कर मारने जा रहे हैं।

कम से कम आउटपुट का उत्पादन करने के लिए संभवतया जानकारी का कम से कम हिस्सा देखें। फिर इस आकार के हिस्सों में इनपुट को विभाजित करने के तरीके के बारे में सोचें।

अब यह आसान लगता है, है ना? (खुशी है कि मुझे यह करने की ज़रूरत नहीं है :))

1

आप स्मृति को इष्टतम तरीके से आवंटित और डिलीकेट नहीं कर रहे हैं। जैसा कि अन्य ने बताया है, आप स्मृति को लीक कर सकते हैं और इसे नहीं जानते हैं। स्मृति आवंटन को डिबग करने और अनुकूलित करने में समय लगेगा।

यदि आप स्मृति उपयोग को अनुकूलित करने में समय बिताना नहीं चाहते हैं, तो Conservative Garbage Collector क्यों न करें? यह malloc()/new और free() के लिए एक प्लग-इन प्रतिस्थापन है। वास्तव में, मुफ्त() एक नो-ऑप है, इसलिए आप केवल उन कार्यक्रमों को अपने प्रोग्राम से हटा सकते हैं। यदि, इसके बजाय, आप अपने प्रोग्राम को हाथ से अनुकूलित करते हैं और पहले सुझाए गए मेमोरी के पूल को प्रबंधित करते हैं, तो आप सीजीसी पहले से ही आपके लिए बहुत सारे काम कर रहे हैं।

1

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

0

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

  • आप Windows पर हैं, तो फ़ाइल मैप्स (sample code) का उपयोग:

    यहाँ कुछ चीजें आप इस स्थिति से बाहर करने में मदद करने के लिए कर सकते हैं। यह एक बफर पॉइंटर के माध्यम से फ़ाइल तक पहुंच प्रदान करेगा जैसे कि आप पूरी फ़ाइल को स्मृति में पढ़ते हैं, केवल वास्तव में ऐसा करने के बिना। लिनक्स कर्नेल के हाल के संस्करणों में एक समान तंत्र है।

  • यदि आप कर सकते हैं, और ऐसा लगता है कि आप अनुक्रमिक रूप से फ़ाइल स्कैन कर सकते हैं और इन-मेमोरी डीओएम बनाने से बच सकते हैं। इससे आपके लोड-टाइम और मेमोरी आवश्यकताएं बहुत कम हो जाएंगी।
  • पूल मेमोरी का उपयोग करें! आपके पास शायद कई छोटी वस्तुएं होंगी, जैसे कि नोड्स, पॉइंट्स और व्हाट्नॉट। मदद करने के लिए पूल की गई मेमोरी का उपयोग करें (मुझे लगता है कि आप एक अप्रबंधित भाषा का उपयोग कर रहे हैं। पूल आवंटन और मेमोरी पूल के लिए खोजें)।
  • यदि आप एक प्रबंधित भाषा का उपयोग कर रहे हैं, तो कम से कम इस विशेष भाग को एक अप्रबंधित भाषा में ले जाएं और स्मृति और फ़ाइल पढ़ने पर नियंत्रण रखें। प्रबंधित भाषाओं में मेमोरी पदचिह्न और प्रदर्शन दोनों में एक गैर-तुच्छ ओवरहेड होता है। (हाँ, मुझे पता है कि यह टैग किया गया है "सी ++" ...)
  • एक जगह में एल्गोरिदम तैयार करने का प्रयास, जहां आप एक समय में केवल न्यूनतम मात्रा में डेटा पढ़ते हैं और संसाधित करते हैं, इसलिए आपकी मेमोरी आवश्यकताएं नीचे आ जाएंगी।

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

0

इसके लिए एक अच्छी तकनीक है, फाइलों में कुछ उदाहरणों को स्टोर करना है, और उन्हें प्राप्त करने के बाद उन्हें प्राप्त करने के बाद।

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

0

के बाद से मैं हाल ही में एक ही बात किया है यह, एक पुराने सवाल है, लेकिन ....

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

असल में मैं अभी भी क्षमता के कारणों के लिए एक्सपी 32 बिट का उपयोग कर रहा हूं।

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

32 बिट मशीन पर एक छोटे पदचिह्न में यह सब काम करने के लिए मुझे एकमात्र तरीका यह था कि मैं क्या कर रहा था और कार्यों में कार्य को तोड़ने और तोड़ने की आवश्यकता के बारे में बहुत सावधानी से सोचना था। मेमोरी कुशल (कभी भी 100 एमबी से अधिक का उपयोग नहीं करता है) लेकिन बड़े पैमाने पर तेज़ नहीं है, लेकिन फिर इससे कोई फर्क नहीं पड़ता - कितनी बार एक्सएमएल डेटा को पार्स करना पड़ता है?

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