2011-10-14 19 views
11

से आने वाले बड़े ऑब्जेक्ट हीप और स्ट्रिंग ऑब्जेक्ट्स में मेरे पास एक विंडोज कंसोल ऐप है जिसे बिना दिन और महीनों के पुनरारंभ किए बिना चलाने के लिए माना जाता है। ऐप एक एमएसएमक्यू से "काम" पुनर्प्राप्त करता है और इसे संसाधित करता है। ऐसे 30 धागे हैं जो एक साथ काम की प्रक्रिया को संसाधित करते हैं।एक कतार

एमएसएमक्यू से आने वाले प्रत्येक कार्य खंड लगभग 200kb है जिसमें से अधिकांश एकल स्ट्रिंग ऑब्जेक्ट में आवंटित किया जाता है।

मैंने देखा है कि इन कामों के लगभग 3-4 हजार प्रोसेसिंग के बाद आवेदन की स्मृति खपत हास्यास्पद रूप से 1 - 1.5 जीबी स्मृति का उपभोग कर रही है।

मैं एक प्रोफाइलर के माध्यम से ऐप चलाता हूं और ध्यान देता हूं कि इस स्मृति में से अधिकांश (शायद एक गीगा या तो) बड़े ऑब्जेक्ट ढेर में उपयोग नहीं किया जाता है लेकिन संरचना खंडित होती है।

मुझे पता चला है कि इनमें से 9 0% अप्रयुक्त (कचरा एकत्रित) बाइट्स पहले स्ट्रिंग आवंटित किए गए थे। मैंने संदेह करना शुरू कर दिया कि एमएसएमक्यू से आने वाले तारों को आवंटित किया गया था, इस्तेमाल किया गया था और फिर विघटित किया गया था और इसलिए विखंडन का कारण है।

मैं समझता हूं कि जीसी.कोलेक्ट (2 या जीसी.मैक्स ...) जैसी चीजें मदद नहीं करती हैं क्योंकि वे बड़े ऑब्जेक्ट ढेर को जीसी करते हैं लेकिन इसे कॉम्पैक्ट नहीं करते हैं (जो यहां समस्या है)। तो मुझे लगता है कि मुझे इन स्ट्रिंग्स को कैश करना और उन्हें किसी भी तरह से फिर से उपयोग करना है, लेकिन स्ट्रिंग्स अपरिवर्तनीय हैं, इसलिए मुझे स्ट्रिंगबिल्डर का उपयोग करना होगा।

मेरा प्रश्न है: क्या अंतर्निहित संरचना को बदलने के लिए वैसे भी है (यानी एमएसएमक्यू का उपयोग करना क्योंकि यह कुछ ऐसा नहीं है जिसे मैं बदल नहीं सकता) और फिर भी LOH को खंडित करने से बचने के लिए हर बार एक नई स्ट्रिंग शुरू करने से बचें?

धन्यवाद, Yannis

अद्यतन: के बारे में कैसे इन "काम" मात्रा वर्तमान में वर्तमान में

प्राप्त किए गए हैं इन MSMQ में WorkChunk वस्तुओं के रूप में जमा हो जाती है। इन वस्तुओं में से प्रत्येक में स्ट्रिंग नामक एक स्ट्रिंग और हेडर नामक एक और स्ट्रिंग होता है। ये वास्तविक पाठ डेटा हैं। यदि आवश्यक हो तो मैं स्टोरेज स्ट्रक्चर को किसी और चीज में बदल सकता हूं और संभावित रूप से अंतर्निहित स्टोरेज तंत्र को एमएसएमक्यू की तुलना में किसी और चीज की आवश्यकता हो सकती है।

कार्यकर्ता नोड्स तरफ वर्तमान में हम करते हैं

WorkChunk हिस्सा = _Queue.Receive();

तो इस चरण में हम बहुत कम कैश कर सकते हैं। अगर हमने संरचना को किसी भी तरह बदल दिया तो मुझे लगता है कि हम कुछ प्रगति कर सकते हैं। किसी भी मामले में, हमें इस समस्या को हल करना होगा ताकि काम के महीनों को फेंकने से बचने के लिए हम जो कुछ भी कर सकें, हम करेंगे।

अद्यतन: मैंने नीचे दिए गए कुछ सुझावों को आजमाया और देखा कि यह समस्या मेरी स्थानीय मशीन (विंडोज 7 x64 और 64 बिट ऐप चलाने) पर पुन: उत्पन्न नहीं की जा सकती है। यह चीजों को और अधिक कठिन बनाता है - अगर कोई जानता है कि क्यों यह वास्तव में स्थानीय रूप से इस मुद्दे को पुनर्निर्मित करने में मदद करेगा।

+0

आप उन तारों को कैसे प्राप्त करते हैं? एक बार वे तार हैं तो आप अटक गए हैं। मैं वे एक धारा या बाइट से आते हैं [] आपके पास कुछ विकल्प हो सकते हैं। –

+0

हाय हेनक - इन कामों के बारे में अधिक जानकारी प्राप्त करने के लिए अद्यतन पर एक नज़र डालें – Yannis

+0

लेकिन क्या यह एक वास्तविक समस्या है? एक 64 बिट पीसी पर 1.5 जीबी> = 8 जीबी रैम जारी रखने में सक्षम होना चाहिए। –

उत्तर

4

आपकी समस्या बड़ी वस्तु ढेर पर स्मृति आवंटन की वजह से प्रतीत होता है - बड़ी वस्तु ढेर जमा नहीं है और इसलिए विखंडन का एक स्रोत हो सकता है।

Large Object Heap Uncovered

आप दो तीन समाधान दिखाई देते हैं: वहाँ यहाँ एक अच्छा लेख है कि कुछ डिबगिंग चरण हैं, जो आप बड़ी वस्तु ढेर के कि विखंडन पुष्टि करने के लिए अनुसरण कर सकते हैं सहित और अधिक विस्तार में चला जाता है हो रहा है:

  1. भाग/छोटे तारों पर प्रसंस्करण करने के लिए अपने आवेदन को बदलें, जहां प्रत्येक खंड 85,000 बाइट से छोटा है - इससे बड़ी वस्तुओं के आवंटन से बचा जाता है।
  2. स्मृति सामने और बदले आबंटित स्मृति में नए संदेशों को कॉपी करके उन टुकड़ों को फिर से उपयोग करने के कुछ ही बड़े हिस्से का आवंटन करने के लिए अपने आवेदन में परिवर्तन। Heap fragmentation when using byte arrays देखें।
  3. छोड़ दो चीजों के रूप में वे कर रहे हैं - जब तक आप स्मृति अपवाद से बाहर का अनुभव नहीं है के रूप में और आवेदन प्रणाली के रूप में वे कर रहे हैं तो आप शायद चीजों को छोड़ देना चाहिए पर चल रहे अन्य अनुप्रयोगों के साथ हस्तक्षेप नहीं है।

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

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

+0

धन्यवाद जस्टिन का प्रयास करें। समस्या यह है कि ये स्ट्रिंग्स एक संदेश कतार के माध्यम से एक अलग सिस्टम से आती हैं। तो मैं नहीं कह सकता कि "उस वर्क खंड का आधा हिस्सा प्राप्त करें" वर्तमान में जब तक मैं समग्र स्टोरेज संरचना नहीं बदलता - और मुझे लगता है कि मुझे विचारों और सुझावों की आवश्यकता है – Yannis

+0

@Yannis यदि आप अपना आवेदन बदलना चाहते हैं तो यह इस तरह से दिखता है - सुझावों के लिए इस पर किए जा रहे प्रसंस्करण के तरीके पर आप इसे और अधिक विस्तार से कैसे करना चाहते हैं, शायद इसकी आवश्यकता है। क्या आपने अपना नवीनतम संपादन देखा है? आपको यह समझना चाहिए कि आप जो व्यवहार देख रहे हैं वह पूरी तरह से ठीक हो सकता है (जब तक आपको ओओएम अपवाद नहीं मिलते हैं, क्या यह 32 बिट या 64 बिट प्रक्रिया है?) – Justin

+0

जस्टिन - यह 64 बिट प्रक्रिया है और परिणाम यह है कि कंप्यूटर (विंडोज 2008 सर्वर) अत्यधिक पेजिंग के कारण क्रॉल में धीमा हो जाता है। यह समझ में आता है। मुझे यह पूछने दो: यदि मैं स्ट्रिंग सामग्री गुण को char [] [] में बदलता हूं जिसमें 85k के चार भाग के चार सरणी (LOH पर कुछ डालने की सीमा) शामिल है - क्या इससे मदद मिलेगी? – Yannis

1

शायद आप स्ट्रिंग ऑब्जेक्ट्स का एक पूल बना सकते हैं जिसका उपयोग आप काम को संसाधित करते समय उपयोग कर सकते हैं और फिर समाप्त होने के बाद वापस लौट सकते हैं।

LOH में एक बड़ी वस्तु बनने के बाद, इसे हटाया नहीं जा सकता है (AFAIK), इसलिए यदि आप इन वस्तुओं को बनाने से नहीं बच सकते हैं तो सबसे अच्छी योजना उनका पुन: उपयोग करना है।

यदि आप दोनों सिरों पर प्रोटोकॉल बदल सकते हैं, तो अपने 'सामग्री' स्ट्रिंग को छोटे (< 80k प्रत्येक) के सेट में कम करने से उन्हें LOH में संग्रहीत होने से रोकना चाहिए।

+0

चलने वाला एक (सटीक) सिमुलेशन चल रहा है जो ओपी पहले से ही कहा गया है। लेकिन _how_ क्या आप एक स्ट्रिंग का पुन: उपयोग करते हैं? –

+0

अधिक जानकारी के साथ मूल पोस्ट में एक संपादन जोड़ा गया – Yannis

+0

टोनी - समस्या इन सामग्रियों को क्रमबद्ध कर रही है और दूसरी तरफ उन्हें deserializing है। जो कुछ भी मैं इस वस्तु में करता हूं वह इन "सामग्रियों" को एक या दूसरे तरीके से रखेगा - यहां तक ​​कि छोटे हिस्सों में भी। – Yannis

2

जब LOH पर विखंडन नहीं है, इसका मतलब है कि वहाँ पर वस्तुओं आवंटित किए जाते हैं। यदि आप विलंब को पूरा कर सकते हैं, तो आप एक बार प्रतीक्षा कर सकते हैं जब तक कि वर्तमान में चल रहे सभी कार्य समाप्त नहीं हो जाते हैं और GC.Collect() पर कॉल करें। जब कोई संदर्भित बड़ी वस्तुएं नहीं होती हैं, तो वे सभी को एकत्रित किया जाएगा, प्रभावी रूप से LOH के विखंडन को हटा दिया जाएगा। बेशक यह केवल तभी काम करता है जब (सभी) सभी बड़ी वस्तुओं को संदर्भित नहीं किया जाता है।

इसके अलावा, 64 बिट ओएस पर जाने से भी मदद मिल सकती है, क्योंकि विखंडन के कारण स्मृति से बाहर 64 बिट सिस्टम पर समस्या होने की संभावना कम होती है, क्योंकि वर्चुअल स्पेस लगभग असीमित है।

+0

स्टीवन मुझे लगता है कि आप गलत हैं क्योंकि विखंडन का मतलब यह नहीं है कि वस्तुएं हैं (LOH में) लेकिन वे एक बार वहां थे और अंत में डी आवंटित हो गए इस प्रकार LOH में एक खाली हिस्सा छोड़कर। इसका मतलब यह है कि यदि 120k (कहें) का एक हिस्सा है और हम 121k आवंटित करने की कोशिश कर रहे हैं तो यह 121k बाइट्स के पहले उपलब्ध संगत खंड में आवंटित किया जाएगा जिससे 120k खंड खाली हो जाएगा। जीसी.कोलेक्ट() दुर्भाग्य से केवल एलओएच ऑब्जेक्ट्स को आवंटित करेगा (और उस जीसी.कोलेक्ट (जीसी.मैक्सजनेशन) की आवश्यकता है) और LOH को कॉम्पैक्ट नहीं करें। – Yannis

+1

मुझे नहीं लगता कि स्टीवन कह रहा है कि जीसी। कोलेक्ट कॉम्पैक्ट करेगा, मुझे लगता है कि वह कह रहा है जब आप केवल कुछ ऑब्जेक्ट्स पर जाते हैं। इस तरह से यह बड़ी वस्तुओं से छुटकारा पायेगा, जिसके बीच आपको एक अच्छा (आईएसएच) साफ स्लेट के साथ छोड़ने वाले अंतर हैं। – Joey

+1

@ यैनिस: मैं जो कह रहा हूं वह है: एक खाली LOH खंडित नहीं किया जा सकता है। जॉय ने इसे अच्छी तरह से दोहराया। – Steven

0

कैसे डुप्लिकेट संदर्भ को खत्म करने String.Intern (...) का उपयोग कर के बारे में। इसमें एक प्रदर्शन जुर्माना है, लेकिन आपके तारों के आधार पर इसका असर हो सकता है।

+0

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

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