2009-08-27 19 views
24

मेरे पास django में चल रही एक छोटी मल्टीथ्रेडेड स्क्रिप्ट है और समय के साथ अधिक से अधिक स्मृति का उपयोग शुरू होता है। इसे पूरे दिन छोड़ने के बारे में 6 जीबी रैम खाती है और मैं स्वैप करना शुरू कर देता हूं।पायथन: मेमोरी लीक डीबगिंग

http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks के बाद मैं सबसे आम प्रकार (स्मृति के केवल 800M उपयोग किया जाता के साथ) के रूप में देखते:

(Pdb) objgraph.show_most_common_types(limit=20) 
dict      43065 
tuple      28274 
function     7335 
list      6157 
NavigableString   3479 
instance     2454 
cell      1256 
weakref     974 
wrapper_descriptor   836 
builtin_function_or_method 766 
type      742 
getset_descriptor   562 
module      423 
method_descriptor   373 
classobj     256 
instancemethod    255 
member_descriptor   218 
property     185 
Comment     183 
__proxy__     155 

जो कुछ भी अजीब नहीं दिखाती है। स्मृति समस्याओं को डीबग करने में मदद करने के लिए अब मुझे क्या करना चाहिए?

अद्यतन: कुछ चीजों की कोशिश कर रहे लोगों की सिफारिश कर रहे हैं। मैंने रातोंरात कार्यक्रम चलाया, और जब मैं काम करता हूं, 50% * 8 जी == 4 जी रैम का इस्तेमाल किया जाता है।

(Pdb) from pympler import muppy 
(Pdb) muppy.print_summary() 
            types | # objects | total size 
========================================== | =========== | ============ 
            unicode |  210997 |  97.64 MB 
             list |  1547 |  88.29 MB 
             dict |  41630 |  13.21 MB 
             set |   50 |  8.02 MB 
             str |  109360 |  7.11 MB 
            tuple |  27898 |  2.29 MB 
             code |  6907 |  1.16 MB 
             type |   760 | 653.12 KB 
            weakref |  1014 |  87.14 KB 
             int |  3552 |  83.25 KB 
        function (__wrapper__) |   702 |  82.27 KB 
         wrapper_descriptor |   998 |  77.97 KB 
             cell |  1357 |  74.21 KB 
    <class 'pympler.asizeof.asizeof._Claskey |  1113 |  69.56 KB 
         function (__init__) |   574 |  67.27 KB 

यह 4 जी तक नहीं है, और न ही मुझे ठीक करने के लिए कोई बड़ा डेटा संरचित किया गया है। यूनिकोड "किए गए" नोड्स के सेट() से है, और सूची की तरह यादृच्छिक weakref एस है।

मैंने गप्पी का उपयोग नहीं किया क्योंकि इसे सी एक्सटेंशन की आवश्यकता थी और मेरे पास रूट नहीं था इसलिए इसे बनाने के लिए दर्द हो रहा था।

कोई भी ऑब्जेक्ट जिसका उपयोग मैं कर रहा था __del__ विधि है, और पुस्तकालयों के माध्यम से देख रहा है, यह django की तरह नहीं दिखता है और न ही पायथन-mysqldb या तो करता है। कोई अन्य विचार?

+0

"Django में चल रहा है"? क्या आपका मतलब है कि आप अतिरिक्त गैर-वेब-सेवा पृष्ठभूमि प्रसंस्करण करने के लिए Django वेब सर्वर का उपयोग कर रहे हैं? क्या आपने इस गैर-वेब-सेवारत सामग्री को एक अलग प्रक्रिया में विभाजित करने पर विचार किया है? –

+2

यह एक क्रॉन नौकरी है जो Django settgings.py आयात करता है और कई Django ORM सुविधाओं का उपयोग करता है। इसलिए, यह किसी वेबसर्वर द्वारा उत्पन्न नहीं होता है, लेकिन फिर भी कई सुविधाओं का उपयोग करता है (जो प्रासंगिक हो सकता है) –

उत्तर

31

http://opensourcehacker.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/ देखें। संक्षिप्त उत्तर: यदि आप django चला रहे हैं लेकिन वेब-अनुरोध-आधारित प्रारूप में नहीं हैं, तो आपको db.reset_queries() मैन्युअल रूप से चलाने की आवश्यकता है (और निश्चित रूप से DEBUG = गलत है, जैसा कि अन्य ने उल्लेख किया है)। वेब अनुरोध के बाद Django स्वचालित रूप से reset_queries() करता है, लेकिन आपके प्रारूप में, ऐसा कभी नहीं होता है।

+2

db.reset_queries() ने मेरे लिए एक समस्या हल की, बहुत बहुत धन्यवाद। – pyeleven

0

Guppy आज़माएं।

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

1

मुझे लगता है कि आपको विभिन्न टूल्स का उपयोग करना चाहिए। जाहिर है, आपके द्वारा प्राप्त आंकड़े केवल जीसी वस्तुओं के बारे में हैं (यानी वस्तुएं जो चक्रों में भाग ले सकती हैं); सबसे विशेष रूप से, इसमें तारों की कमी है।

मैं Pympler का उपयोग करने की सलाह देता हूं; यह आपको अधिक विस्तृत आंकड़े प्रदान करेगा।

+0

शीर्ष 7% * 8GB = 560M का उपयोग करके मेरा ऐप दिखाता है। pympler.muppy.print_summary() लगभग 55 मीटर दिखाता है। बाकी कहाँ है? –

6

क्या आपने gc.set_debug() को आजमाया है?

आप अपने आप को सरल सवाल पूछने की जरूरत है:

  • मैं __del__ तरीकों के साथ वस्तुओं का उपयोग कर रहा हूं? क्या मैं बिल्कुल, स्पष्ट रूप से, उन्हें चाहिए?
  • क्या मुझे अपने कोड में संदर्भ चक्र मिल सकते हैं? क्या वस्तुओं से छुटकारा पाने से पहले हम इन सर्किलों को तोड़ नहीं सकते?

    import gc 
    
    class A(object): 
        def __del__(self): 
         print 'a deleted' 
         if hasattr(self, 'b'): 
          delattr(self, 'b') 
    
    class B(object): 
        def __init__(self, a): 
         self.a = a 
        def __del__(self): 
         print 'b deleted' 
         del self.a 
    
    
    def createcycle(): 
        a = A() 
        b = B(a) 
        a.b = b 
        return a, b 
    
    gc.set_debug(gc.DEBUG_LEAK) 
    
    a, b = createcycle() 
    
    # remove references 
    del a, b 
    
    # prints: 
    ## gc: uncollectable <A 0x...> 
    ## gc: uncollectable <B 0x...> 
    ## gc: uncollectable <dict 0x...> 
    ## gc: uncollectable <dict 0x...> 
    gc.collect() 
    
    # to solve this we break explicitely the cycles: 
    a, b = createcycle() 
    del a.b 
    
    del a, b 
    
    # objects are removed correctly: 
    ## a deleted 
    ## b deleted 
    gc.collect() 
    

    मैं वास्तव में झंडा वस्तुओं/अवधारणाओं कि आपके आवेदन में साइकिल चालन कर रहे हैं करने के लिए प्रोत्साहित करने और उनके जीवन पर ध्यान केंद्रित करेंगे:

देखें, मुख्य मुद्दा __del__ तरीकों से युक्त वस्तुओं की एक चक्र होगा: जब आपको अब उनकी आवश्यकता नहीं है, तो क्या हमारे पास इसका कुछ संदर्भ है?

यहां तक ​​कि चक्र के लिए

__del__ बिना तरीकों, हमने ऐसी समस्या हो सकती है:

import gc 

# class without destructor 
class A(object): pass 

def createcycle(): 
    # a -> b -> c 
    #^  | 
    # ^<--<--<--| 
    a = A() 
    b = A() 
    a.next = b 
    c = A() 
    b.next = c 
    c.next = a 
    return a, b, b 

gc.set_debug(gc.DEBUG_LEAK) 

a, b, c = createcycle() 
# since we have no __del__ methods, gc is able to collect the cycle: 

del a, b, c 
# no panic message, everything is collectable: 
##gc: collectable <A 0x...> 
##gc: collectable <A 0x...> 
##gc: collectable <dict 0x...> 
##gc: collectable <A 0x...> 
##gc: collectable <dict 0x...> 
##gc: collectable <dict 0x...> 
gc.collect() 

a, b, c = createcycle() 

# but as long as we keep an exterior ref to the cycle...: 
seen = dict() 
seen[a] = True 

# delete the cycle 
del a, b, c 
# nothing is collected 
gc.collect() 

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

मैं अब set_debug द्वारा थोड़ा निराश हूं, मेरी इच्छा है कि इसे stderr से कहीं और डेटा आउटपुट करने के लिए कॉन्फ़िगर किया जा सके, लेकिन उम्मीद है कि that should change soon

+0

gc.collect() सबकुछ एकत्रित करने के रूप में वापस कर रहा है, और दूसरे आमंत्रण पर 0 देता है। इसका मतलब है कि मेरे पास कोई चक्र सही नहीं है? –

+0

@ पॉल: नहीं, आप अभी भी चक्र कर सकते हैं। मैंने जो आखिरी उदाहरण दिया है उसे देखें: यहां, gc.collect() 0 लौटाता है, और कुछ भी मुद्रित नहीं होता है। यदि आपके पास ऑब्जेक्ट्स के चक्र हैं जिनके पास __del__ विधियां नहीं हैं, तो जीसी शांत रहेगी। – NicDumZ

1

क्या आप किसी भी एक्सटेंशन का उपयोग करते हैं? वे स्मृति रिसाव के लिए एक अद्भुत जगह हैं, और पाइथन उपकरण द्वारा ट्रैक नहीं किया जाएगा।

+0

कोई एक्सटेंशन नहीं है, लेकिन देखने के लिए यहां ठोकरें दूसरों के लिए एक अच्छी जगह है। –

+0

यदि आप Django ORM का उपयोग करते हैं, तो आप एक्सटेंशन मॉड्यूल - डीबी-एपीआई डेटाबेस ड्राइवर का उपयोग करते हैं। क्या यह MySQLdb है? मौजूदा संस्करण कर्सर मेमोरी रिसाव को जानता है जब कनेक्शन use_unicode = True के साथ स्थापित होता है (जो Django> = 1.0 के लिए मामला है)। – zgoda

+0

हाँ, आप पैसे पर सही हैं! मैं उन सभी का उपयोग कर रहा हूँ। कोई ज्ञात समाधान? –

19

क्या DEBUG = सेटिंग.py में गलत है?

यदि Django आपके द्वारा बनाए गए सभी SQL प्रश्नों को खुशी से स्टोर नहीं करेगा।

+2

वाह, मुझे पता था कि वहां django शब्द लिखने में मदद मिलेगी। हां, मेरी स्क्रिप्ट मेरी उत्पादन सेटिंग्स का उपयोग नहीं कर रही थी। *शर्मिंदा*। चलो देखते हैं कि यह स्मृति समस्या को साफ़ करता है या नहीं। –

+0

यह है! बड़े डेटाबेस से चयन करते समय DEBUG सत्य पर सेट वास्तव में बहुत सारी मेमोरी खाती है। –

5

this excellent blog post from Ned Batchelder देखें कि कैसे उन्होंने एचपी के टैब्लो में वास्तविक मेमोरी लीक का पता लगाया। एक क्लासिक और लायक पढ़ने।

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