2010-04-02 25 views
12

मैं डेल्फी 200 का उपयोग कर रहा हूं जिसमें फास्टएमएम 4 मेमोरी मैनेजर है।मेरा डेल्फी प्रोग्राम की स्मृति क्यों बढ़ती जा रही है?

मेरा प्रोग्राम एक बड़े डेटासेट को पढ़ता है और संसाधित करता है। जब भी मैं डेटासेट साफ़ करता हूं या प्रोग्राम से बाहर निकलता हूं तो सभी मेमोरी सही ढंग से मुक्त हो जाती है। इसमें कोई स्मृति रिसाव नहीं है।

स्पैनवार के उत्तर में दिए गए CurrentMemoryUsage दिनचर्या का उपयोग करना: How to get the Memory Used by a Delphi Program, मैंने प्रसंस्करण के दौरान FastMM4 द्वारा उपयोग की गई स्मृति प्रदर्शित की है।

ऐसा लगता है कि प्रत्येक प्रक्रिया और रिलीज चक्र के बाद स्मृति का उपयोग बढ़ रहा है। उदाहरण:

1,456 KB कोई प्रोग्रामसेट के साथ अपना प्रोग्राम शुरू करने के बाद उपयोग किया जाता है।

218,455 KB एक बड़ा डेटासेट लोड करने के बाद उपयोग किया जाता है।

71,994 KB डेटासेट को पूरी तरह साफ़ करने के बाद। अगर मैं इस बिंदु से बाहर निकलता हूं (या मेरे उदाहरण में कोई भी बिंदु), तो कोई मेमोरी लीक की सूचना नहीं दी जाती है।

271,905 KB उसी डेटासेट को फिर से लोड करने के बाद उपयोग किया जाता है।

125,443 KB डेटासेट को पूरी तरह साफ़ करने के बाद।

325,519 KB उसी डेटासेट को फिर से लोड करने के बाद उपयोग किया जाता है।

179,059 KB डेटासेट को पूरी तरह साफ़ करने के बाद।

378,752 KB उसी डेटासेट को फिर से लोड करने के बाद उपयोग किया जाता है।

ऐसा लगता है कि प्रत्येक लोड/स्पष्ट चक्र पर मेरे प्रोग्राम की मेमोरी उपयोग लगभग 53,400 केबी बढ़ रही है। कार्य प्रबंधक पुष्टि करता है कि यह वास्तव में हो रहा है।

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

क्या कोई जानता है कि यह क्यों हो रहा है, यदि यह बुरा है, और यदि कुछ भी है तो मैं इसके बारे में क्या कर सकता हूं या कर सकता हूं?


धन्यवाद आपके जवाब के लिए dthorpe और मेसन। तुमने मुझे उन चीजों को सोचने और कोशिश करने की कोशिश की जो मुझे एहसास हुआ कि मुझे कुछ याद आ रहा था। तो विस्तृत डिबगिंग की आवश्यकता थी।

जैसा कि यह पता चला है, मेरे सभी ढांचे को बाहर निकलने पर ठीक से मुक्त किया जा रहा था। लेकिन रन के दौरान प्रत्येक चक्र के बाद स्मृति रिलीज नहीं था। यह मेमोरी ब्लॉक जमा कर रहा था जो आमतौर पर एक रिसाव का कारण बनता था जो बाहर निकलने पर पता लगाने योग्य होता अगर मेरा निकास सफाई सही नहीं था - लेकिन यह था।

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

इस प्रश्न का उत्तर दिया गया है। आपकी सहायता के लिए धन्यवाद.

+0

IMHO, आप अपने जवाब जोड़ा गया है और बजाय सवाल संपादन के इसे स्वीकार कर लिया जाना चाहिए था। प्रश्न, उत्तर और अपने अनुभव से सीखने के लिए किसी की देखभाल करना आसान है। – EMBarbosa

उत्तर

25

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

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

अधिक जानकारी में इसे प्राप्त करने के लिए: आपका डेल्फी एप्लिकेशन मेमोरी को काफी छोटे हिस्सों में आवंटित करता है - यहां एक स्ट्रिंग, एक कक्षा है। एक कार्यक्रम के लिए औसत स्मृति आवंटन आमतौर पर कुछ सौ बाइट से कम होता है। सिस्टम आवंटन पैमाने पर इस तरह के छोटे आवंटन को प्रबंधित करना मुश्किल है, इसलिए ऑपरेटिंग सिस्टम नहीं है। यह बड़ी मेमोरी ब्लॉक कुशलता से प्रबंधित करता है, खासकर 4k वर्चुअल मेमोरी पेज आकार और 64k वर्चुअल मेमोरी एड्रेस न्यूनतम आकारों पर।

यह अनुप्रयोगों के लिए एक समस्या प्रस्तुत करता है: अनुप्रयोग आमतौर पर छोटे हिस्सों को आवंटित करते हैं, लेकिन ओएस बड़े हिस्सों में स्मृति को बाहर निकाल देता है। क्या करें? उत्तर: suballocate।

डेल्फी रनटाइम लाइब्रेरी के मेमोरी मैनेजर और फास्टएमएम प्रतिस्थापन मेमोरी मैनेजर (और ग्रह पर लगभग हर दूसरी भाषा या टूलसेट की रनटाइम लाइब्रेरी) दोनों एक काम करने के लिए मौजूद हैं: ओएस से बड़े मेमोरी ब्लॉक को छोटे में बनाएं आवेदन द्वारा इस्तेमाल ब्लॉक। जहां सभी छोटे ब्लॉक हैं, वे कितने बड़े हैं, और क्या उन्हें "लीक" किया गया है, इस बारे में ट्रैक रखना चाहिए कि कुछ मेमोरी के साथ-साथ ओवरहेड भी कहा जाता है।

भारी मेमोरी आवंटन/डीलोकेशन की स्थितियों में, ऐसी स्थितियां हो सकती हैं जिनमें आप आवंटित किए गए 99% को हटा देते हैं, लेकिन प्रक्रिया के कामकाजी सेट आकार केवल 50% कहते हैं। क्यूं कर? अक्सर, यह ढेर विखंडन के कारण होता है: ओएस से प्राप्त डेल्फी मेमोरी मैनेजर को आंतरिक रूप से विभाजित करने वाले बड़े ब्लॉक में से एक में स्मृति का एक छोटा सा ब्लॉक अभी भी उपयोग में है। उपयोग की गई स्मृति की आंतरिक गणना छोटी है (300 बाइट्स, कहें) लेकिन चूंकि यह हेप मैनेजर को ओएस पर वापस आने वाले बड़े ब्लॉक को छोड़ने से रोक रहा है, इसलिए उस छोटे से 300 बाइट खंड का कामकाजी सेट योगदान 4k (या 64k इस पर निर्भर करता है कि यह वर्चुअल पेज या वर्चुअल एड्रेस स्पेस है - मुझे याद नहीं है)।

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

यह देखने के लिए कि यह आपके कामकाजी सेट को कम करता है, कम से कम विंडो चाल का प्रयास करें। यदि ऐसा होता है, तो आप कार्य सेट काउंटर द्वारा लौटाई गई संख्याओं की स्पष्ट "गंभीरता" को छूट सकते हैं। आप अपने बड़े कंप्यूट ऑपरेशन के बाद उन पृष्ठों को शुद्ध करने के लिए SetProcessWorkingSetSize पर एक कॉल भी जोड़ सकते हैं जो अब उपयोग में नहीं हैं।

+0

उसे यह नहीं देखना चाहिए कि विखंडन ढेर के लिए खो गई बहुत याददाश्त। फास्टएमएम विशेष रूप से विखंडन को पूर्ण न्यूनतम रखने के लिए डिज़ाइन किया गया है। –

+5

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

+0

धन्यवाद लेकिन कम से कम न्यूनतम प्रभाव पड़ा और समस्या को ठीक नहीं किया। मैंने गैबर की मेमोरी क्लीनअप रूटीन को भी आजमाया: http://stackoverflow.com/questions/2031577/can-memory-be-cleaned-up/2033393#2033393 और इससे कोई मदद नहीं मिली। अनुलेख बैरी का जवाब बहुत जानकारीपूर्ण है। – lkessler

1

आप किस प्रकार का डेटासेट उपयोग कर रहे हैं?यदि यह पूरी तरह से डेल्फी में लागू किया गया है, (मिडास जैसे किसी अन्य मेमोरी मैनेजर के साथ अन्य कोड को कॉल नहीं करना), तो आप जानबूझकर डेटासेट को लीक करने का प्रयास कर सकते हैं।

मुझे लगता है कि आपका डेटासेट एक रूप पर है, और जब फॉर्म इसके घटकों को साफ़ करता है तो इसे स्वचालित रूप से मुक्त किया जा रहा है। अपने फॉर्म के OnDestroy में MyDataset := nil; डालने का प्रयास करें। यह सुनिश्चित करेगा कि डेटासेट लीक, और डेटासेट के स्वामित्व वाले सभी कुछ भी। दो बार लोड करने के बाद बार-बार लोड करने के बाद कोशिश करें और रिसाव रिपोर्ट की तुलना करें, और देखें कि इससे आपको कुछ भी उपयोगी लगता है या नहीं।

+0

@ मेसन: शायद मेरा शब्द "डेटासेट" भ्रामक है। डेटासेट द्वारा मेरा मतलब है कि एक बड़े आकार का एक टेक्स्ट या यूनिकोड आधारित इनपुट फ़ाइल जिसे मैं एक फ़ाइलस्ट्रीम के रूप में पढ़ रहा हूं, साथ ही साथ आंतरिक डेटा संरचनाएं जिन्हें मैं बना रहा हूं। मैं डेटाबेस का उपयोग नहीं कर रहा हूँ। मेरा कार्यक्रम एक एकल EXE है। मैं किसी बाहरी डीएलएल को फोन नहीं करता हूं। मेरी संदेह, स्मृति के हिस्से के बड़े आकार के कारण खो गया है, कि उस फाइलस्ट्रीम के साथ कुछ करने के लिए और शायद वह बफर जो मैं लोड कर रहा हूं। लेकिन यूरेकालॉग या एकटाइम द्वारा या तो कोई रिसाव नहीं है। मैं अब भारी डीबगिंग में हूं। – lkessler

0

आप आधे लीकिंग मेमोरी हैं; जाहिर है। प्रोग्राम चल रहा है, जबकि आप स्मृति को लीक कर रहे हैं, लेकिन जब आप प्रोग्राम बंद करते हैं, तो आपका डेटासेट ठीक से मुक्त हो जाता है ताकि फास्टएमएम (सही तरीके से) इसकी रिपोर्ट न करे।

जानकारी के लिए इस देखें: My program never releases the memory back. Why?

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