2009-12-07 15 views
13

में मेमोरी लीक से बचने का सबसे अच्छा तरीका क्या है मेरे पास PRISM पर आधारित एक WPF एप्लिकेशन है जो एमवीवीएम पैटर्न का उपयोग करता है।WPF PRISM/MVVM अनुप्रयोग

मैं देखा है कि कभी-कभी मेरे विचार मॉडल, विचारों और उन्हें से जुड़े सब कुछ अपने इच्छित उम्र के बाद लंबे समय तक के आसपास रखती हूँ।

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

मुझे लगता है कि एक कंपोजिट प्रेजेंटेशन इवेंट का उपयोग करना संभवतः संग्रहChanged की सदस्यता लेने के लिए बेहतर है, लेकिन अन्य परिदृश्यों में मैं IDISposable लागू करने की दिशा में झुका रहा हूं और दृश्य दृश्य मॉडल पर डिस्प्ले विधि को कॉल करता हूं।

लेकिन फिर कुछ जब जो भी कम आकर्षक हो जाता है जब विचारों की जटिलता में वृद्धि को देखते मॉडल, पर निपटान कॉल करने के लिए दृश्य बताने की आवश्यकता होती है, और वे बच्चे विचारों सहित शुरू करते हैं।

आपको क्या लगता है दृश्य मॉडल से निपटने, सुनिश्चित करने के लिए वे स्मृति रिसाव नहीं है करने के लिए सबसे अच्छा तरीका है?

अग्रिम

इयान

उत्तर

14

धन्यवाद मैं आपको बता सकता है कि मैं दर्द आप अनुभव किया है की 100% अनुभव किया है। हम स्मृति रिसाव भाई हैं, मुझे लगता है।

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

<UserControl ... 
      common:LifecycleManagement.CloseHandler="{Binding CloseAction}"> 
... 
</UserControl> 

तो हमारे ViewModel बस प्रकार कार्रवाई की उस पर एक विधि है:

हम क्या किया है एक संलग्न संपत्ति है कि एक दृश्य ViewModel करने के लिए कोई हैंडलर बाध्य करने के लिए अपने आप को लागू कर सकते हैं बनाने है

public MyVM : ViewModel 
{ 
    public Action CloseAction 
    { 
      get { return CloseActionInternal; } 
    } 

    private void CloseActionInternal() 
    { 
      //TODO: stop timers, cleanup, etc; 
    } 
} 

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

यह बस अगर एक दृश्य के DataContext एक IDisposable है देखने के लिए जाँच की एक बहुत राउंडअबाउट रास्ता है, लेकिन यह समय में बेहतर महसूस किया। DataContext की जांच करने में समस्या यह है कि आपके पास उप दृश्य मॉडल हो सकते हैं जिन्हें इस नियंत्रण की भी आवश्यकता है। आपको या तो यह सुनिश्चित करना होगा कि आपके व्यूमोडल्स चेन को इस निपटान कॉल को आगे बढ़ाएं या ग्राफ में सभी विचारों की जांच करें और देखें कि उनके डेटाकॉन्टेक्स आईडीस्पोज़ेबल (यूघ) हैं या नहीं।

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

सबसे अच्छी बात मेरे द्वारा की गई है, तथापि, यह सुनिश्चित कर लें और Redgate मेमोरी प्रोफाइलर की तरह अच्छा स्मृति रिसाव उपकरण है कि मदद से आप वस्तु ग्राफ कल्पना और जड़ वस्तु को ढूंढने का उपयोग करें। यदि आप उस डिस्पैच टाइमर मुद्दे की पहचान करने में सक्षम थे, तो मुझे लगता है कि आप पहले से ही ऐसा कर रहे हैं।

संपादित करें: मैं एक महत्वपूर्ण चीज़ भूल गया। DelegateCommand में ईवेंट हैंडलरों में से एक के कारण संभावित मेमोरी रिसाव है। कोडप्लेक्स पर इसके बारे में एक धागा है जो इसे समझाता है। http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065

प्रिज्म का नवीनतम संस्करण (v2.1) यह तय है। (http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en)।

+0

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

+0

आह यह कस्टम है।जब भी किसी दृश्य को बंद करने की आवश्यकता होती है तो हमारे पास एप्लिकेशन आदेशों के सेट पर एक विधि कॉल की जाएगी। CloseView (ऑब्जेक्ट व्यू)। मैं संलग्न संपत्ति के पीछे स्टोर के साथ जांच करता हूं कि यह देखने के लिए कि उसके दृश्य या उसके किसी भी बच्चे के दृश्य निकट हैंडलर के लिए पंजीकृत हैं या नहीं। यदि ऐसा है, तो मैं उनके द्वारा पंजीकृत विधि को कॉल करता हूं। बाल विचारों का पता लगाने के लिए यहां एकमात्र जादू लॉजिकल ट्रीहेल्पर और विजुअल ट्रीहेल्पर कक्षाओं का उपयोग है। http://msdn.microsoft.com/en-us/library/system.windows.media.visualtreehelper.aspx –

+0

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

2

मेरे निष्कर्ष अब तक ...

प्रिज्म, एकता, WPF और MVVM के अलावा हम भी इकाई की रूपरेखा और Xceed डेटा ग्रिड का उपयोग कर रहे हैं। डॉटट्रेस का उपयोग कर मेमोरी प्रोफाइलिंग किया गया था।

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

दृश्य मॉडल को मूल नियंत्रक वर्ग पर एक स्पष्ट CloseView (UserControl) विधि के भीतर निपटाया गया है। यह दृश्य के डेटाकॉन्टेक्स्ट पर एक आईडीस्पोजेबल ढूंढता है और कॉल पर इसका निपटान करता है।

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

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

यदि आपको इकाई को अद्यतन करने की आवश्यकता नहीं है तो इसे MergeOption के साथ पुनर्प्राप्त करें। अस्वीकरण, विशेष रूप से लंबे समय तक रहने वाले विचारों में जो संग्रह से बंधे हैं।

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

Xceed कॉलम पर CellContentTemplates का उपयोग करते समय गतिशील संसाधनों का उपयोग न करें क्योंकि संसाधन सेल के संदर्भ में होगा, जो बदले में पूरे दृश्य को जीवंत रखेगा।

Xceed कॉलम पर सेलएडिटर का उपयोग करते समय और संसाधन बाहरी संसाधन शब्दकोश में संग्रहीत किया जाता है x: साझा = "False" सेल एडिटर युक्त संसाधन में, एक बार फिर संसाधन सेल का संदर्भ रखेगा, x का उपयोग कर : साझा = "झूठा" सुनिश्चित करता है कि आपको हर बार एक ताजा प्रति प्राप्त हो, पुराने व्यक्ति को सही ढंग से हटाया जा रहा है।

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

+0

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