2013-06-04 14 views
6

Benim python uygulamalarından biri, bellek kullanımını giderek artan bellek kullanımından kaynaklanıyor gibi görünüyor. Benim hipotezim, bunun önüne geçmek için en iyi çabalara rağmen, bir yerlerde döngüsel bir referanstır. Sorunu yalıtmak için, yalnızca hata ayıklama amaçlı bir araç olan erişilemeyen öğeleri manuel olarak kontrol etmenin yollarını araştırıyorum.python'un gc.garbage öğesinin (bellek sızıntılarının izlenmesi için) anlaşılmasıyla ilgili sorun

gc modülü gerekli izleme yeteneğine sahip görünüyor ve son çağrıdan bu yana oluşturulmuş, okunamayan öğelerin bir listesini derlemeyi amaçlayan aşağıdaki kodu denedim. İlk çağrı sadece bir baz kontrol noktasını ayarlar ve ulaşılamaz öğeleri tanımlamaz.

def unreachable(): 
    # first time setup 
    import gc 
    gc.set_threshold(0) # only manual sweeps 
    gc.set_debug(gc.DEBUG_SAVEALL) # keep unreachable items as garbage 
    gc.enable() # start gc if not yet running (is this necessary?) 
    # operation 
    if gc.collect() == 0: 
    return 'no unreachable items' 
    s = 'unreachable items:\n ' \ 
    + '\n '.join('[%d] %s' % item for item in enumerate(gc.garbage)) 
    _deep_purge_list(gc.garbage) # remove unreachable items 
    return s # return unreachable items as text 

Burada, _deep_purge_list döngüleri kesmeyi ve nesneleri el ile kaldırmayı amaçlamaktadır. Aşağıdaki uygulama bazı yaygın durumları ele alır, ancak su geçirmez değildir. İlk sorum, bununla ilgilidir, aşağıya bakın. Çok sınırlı testlere dayanarak kurulumun düzgün şekilde çalıştığı görülüyor. Aşağıdaki döngüsel başvuru doğru bir kez raporlar:

class A(object): 
    def __init__(self): 
    self.ref = self 

print unreachable() 
# no unreachable items 

A() 

print unreachable() 
# unreachable items: 
# [0] <__main__.A object at 0xb74579ac> 
# [1] {'ref': <__main__.A object at 0xb74579ac>} 

print unreachable() 
# no unreachable items 

Ancak garip aşağıdaki şey olur şununla:

print unreachable() 
# no unreachable items 

import numpy 

print unreachable() 
# unreachable items: 
# [0] (<type '_ctypes.Array'>,) 
# [1] {'__module__': 'numpy.ctypeslib', '__dict__': <attribute '__dict__' of 'c_long_Array_1' objects>, '__weakref__': <attribute '__weakref__' of 'c_long_Array_1' objects>, '_length_': 1, '_type_': <class 'ctypes.c_long'>, '__doc__': None} 
# [2] <class 'numpy.ctypeslib.c_long_Array_1'> 
# [3] <attribute '__dict__' of 'c_long_Array_1' objects> 
# [4] <attribute '__weakref__' of 'c_long_Array_1' objects> 
# [5] (<class 'numpy.ctypeslib.c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>) 

print unreachable() 
# unreachable items: 
# [0] (<type '_ctypes.Array'>,) 
# [1] {} 
# [2] <class 'c_long_Array_1'> 
# [3] (<class 'c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>) 

Tekrarlanan invokasyonlar geçen sonucunu dönmeye devam. İçe aktarma işleminden sonra ilk kez erişilemediğinde sorun oluşmaz. Ancak, bu noktada, bu sorunun özgül olduğuna inanıyorum; Benim tahminim yaklaşımımda bir kusur ortaya çıkarır.

Sorularım:

  1. gc.garbage öğeleri kaldırmak için daha iyi bir yolu var mı? İdeal olarak, gc'yi kaldırmanın bir yolu var mıdır, DEBUG_SAVEALL olmadan yapmış mıdır?
  2. Sorunu numpy içe aktarma ile açıklayan herhangi biri olabilir mi ve/veya bunu düzeltmenin yollarını önerebilir mi?

Afterthought:

Bu kod aşağıda amaçlanan yakın performansa sahip olduğunu görüntülenir: gc tarafından sağlanan

def unreachable(): 
    import gc 
    gc.set_threshold(0) 
    gc.set_debug(gc.DEBUG_LEAK) 
    gc.enable() 
    print 'collecting {{{' 
    gc.collect() 
    print '}}} done' 

Ancak, hata ayıklama için ben tipi/id üzerinde zengin dize temsilleri tercih ederim. Ayrıca, eski yaklaşımımdaki kusuru anlamak ve gc modülü hakkında bir şeyler öğrenmek istiyorum.

yardımına takdir ederek,

Gertjan

Güncelleme 05/06:

yerli() hemen önce denirdi sürece, ilk uygulama herhangi ulaşılamaz öğeleri rapor vermedi bir durum ile karşılaştım ona (dönüş değerini atma). Bunun, gc'nin nesne izlemesini nasıl etkileyeceğini anlamıyorum, bu beni daha da şaşırtıyor. Bu sorunu gösteren küçük bir örnek oluşturmanın ne kadar kolay olacağından emin değilim, ancak talep çağıracağından bir çekim yapabilirim.

+0

Sadece bunu gözden geçirdim, ancak "gc.DEBUG_SAVEALL" ifadesini yanlış anlamış olabilirsiniz: serbest bırakılan nesneleri "gc.garbage" öğesine eklemek yeterlidir (yalnızca onları serbest bırakmak yerine). – blueyed

cevap

0

Son kez böyle bir ihtiyacım olduğunda objgraph module'u kullanarak iyi bir etki elde ettim. Doğrudan gc module'dan kolayca alabileceğinizden çok daha doğru bilgiler verir. Maalesef, kullanımını gösteren bir kodum yok.

Aşağı düştüğü bir yer, çağrılan herhangi bir C kodu kütüphanesi tarafından ayrılan bellekte yer alır. Örneğin bir proje PIL kullanıyorsa, C verisi tarafından desteklenen python nesnelerini düzgün bir şekilde yayınlamaması nedeniyle belleği sızmak çok kolaydır. Bu tür nesneleri düzgün bir şekilde kapatmak için C destekli modül bağımlıdır.

+0

Merhaba Samantha, teşekkürler, evet kabul ediyorum, objgraph referanslarını izlemek için harika bir araçtır. Bununla birlikte, bana, 'A' örneğimde görünecek şekilde, bana ulaşılamaz öğelerin bir listesini vermek için nasıl kullanılacağını anlayamadım; get_leaking_objects ile yapılan denemeler başarısız oldu. Blogunda Marius, küresel nesnelerden gelen referansların örneğiyle bellek sızıntılarını açıklıyor, bu yüzden, objektif referansların izlenmesi için objektifin uygun olmayacağına inanıyorum. Eğer bu sonuç yanlışsa, bunların nasıl ortaya çıkarılabileceğini öğrenmek istiyorum. – gertjan