2016-11-28 12 views
5
निम्नलिखित कार्यक्रम के साथ

से बचने के लिए कैसे:दृश्य के साथ मेमोरी लीक

from traits.api import HasTraits, Int, Instance 
from traitsui.api import View 

class NewView(View): 
    def __del__(self): 
     print('deleting NewView') 

class A(HasTraits): 
    new_view = Instance(NewView) 
    def __del__(self): 
     print('deleting {}'.format(self)) 

    a = Int 

    def default_traits_view(self): 
     new_view = NewView('a') 
     return new_view 

a = A() 
del(a) 

रिटर्न

deleting <__main__.A object at 0x12a016a70> 
एकदम सही ढंग से

चल रहा है।

अगर मैं

a = A() 
a.configure_traits() 

और संवाद को बंद करने के बाद कार्य करें:

del(a) 

मैं संदेश एक ही प्रकार है: newview के उल्लेख के बिना

deleting <__main__.A object at 0x12a016650> 

हटाया जा रहा है ।

geneal में, लक्षण और TraitsUI साथ मेमोरी लीक से बचने के लिए अच्छी प्रथाओं क्या हैं?

+1

अच्छा सवाल है, यवेस:

from traits.api import HasTraits, Int, Instance from traitsui.api import View import gc import weakref class NewView(View): pass def report_collection(ref): print("NewView object has been collected") class A(HasTraits): a = Int def default_traits_view(self): new_view = NewView('a') self.view_ref = weakref.ref(new_view, report_collection) return new_view def open_view(): a = A() a.configure_traits() print("Collecting cyclic garbage") gc.collect() print("Cyclic garbage collection complete") 

मेरी मशीन पर, यहाँ है कि मैं क्या जब open_view कहा जाता है देखते हैं । मेरा पहला (बहुत ही टिकाऊ) अनुमान यह है कि क्योंकि दृश्य हल्के होते हैं और बढ़ने की उम्मीद नहीं होती है, इसे एक महत्वपूर्ण समस्या नहीं माना जाता है। मेरा दूसरा अनुमान यह है कि छिपा जादू है। :) मैंने एक स्पष्टीकरण के लिए कुछ TraitsUI जादूगरों से पूछा है। अगर हमें कोई जवाब नहीं मिलता है, तो मैं एक TraitsUI मुद्दे के रूप में पोस्ट करने का सुझाव दूंगा जहां यह समय के साथ दृश्यता बनाए रखेगा। –

उत्तर

4

यहां क्या हो रहा है यह है कि NewView ऑब्जेक्ट एक संदर्भ चक्र में शामिल है, और उस चक्र में ऑब्जेक्ट्स स्वचालित रूप से सीपीथॉन के प्राथमिक संदर्भ-गणना-आधारित ऑब्जेक्ट डेलोकेशन तंत्र के हिस्से के रूप में एकत्र नहीं होते हैं। हालांकि, उन्हें अंततः सीपीथॉन के चक्रीय कचरा कलेक्टर के हिस्से के रूप में एकत्र किया जाना चाहिए, या आप gc.collect() करके उस संग्रह को मजबूर कर सकते हैं, इसलिए यहां कोई वास्तविक दीर्घकालिक स्मृति रिसाव नहीं होनी चाहिए।

विडंबना यह है कि NewView करने के लिए एक __del__ विधि जोड़कर कि अंतिम संग्रह का पता लगाने का प्रयास कर प्रक्रिया में बाधा है, क्योंकि यह NewView वस्तु uncollectable renders: अजगर 2 में कम से कम, अजगर ऑब्जेक्ट है __del__ युक्त चक्र लेने की कोशिश नहीं करेंगे तरीकों। विवरण के लिए gc docs देखें। तो __del__ विधि के साथ, अजगर 2 का उपयोग कर, वहाँ वास्तव में समय के साथ एक धीमी गति से स्मृति रिसाव हो जाएगा (अजगर 3 कुछ हद तक चालाक यहाँ, PEP 442 में उल्लिखित परिवर्तन करने के लिए धन्यवाद है।)। समाधान __del__ विधि को निकालना है।

यहां एक संदर्भ ग्राफ दिखा रहा है (वास्तव में, यह NewView ऑब्जेक्ट युक्त ऑब्जेक्ट ग्राफ़ के पूरे दृढ़ता से जुड़े घटक को दिखाता है): नोड्स वस्तुएं शामिल हैं, और तीर संदर्भकर्ताओं से रेफरेंस तक जाते हैं। ग्राफ के नीचे दाईं ओर भाग में, आप उस NewView वस्तु अपने शीर्ष स्तर के Group (content विशेषता के माध्यम से) के लिए एक संदर्भ है देखते हैं, और कि Group वस्तु एक संदर्भ वापस (container विशेषता) मूल दृश्य पर है। दृश्य में कहीं और चल रहे चक्र हैं।

NewView reference cycle

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

यहाँ कुछ कोड को दर्शाता है कि कि (__del__ तरीकों के साथ निकाला गया) gc.collect के लिए एक कॉल NewView वस्तु एकत्रित करता है एकत्र किया हुआ। रिसाव प्रतीत होता है अपने `new_view` करने के लिए एक` weakref` साथ कुछ त्वरित प्रयोग से इसकी पुष्टि के साथ,

>>> open_view() 
Collecting cyclic garbage 
NewView object has been collected 
Cyclic garbage collection complete 
+0

बहुत विस्तृत उत्तर के लिए धन्यवाद। मुझे परिणाम प्राप्त करने के लिए अपने कोड के लिए अपने मैक पर 'new_view'definition' में 'kind =' modal'' जोड़ना पड़ा। मैं चाको प्लॉट्स और विशाल (15 मेपिक्स) छवियों के साथ इन क्षणिक विचारों का उपयोग कर रहा था, और मैं स्मृति को विस्फोट कर रहा था –

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