2010-03-11 15 views
31

Bir ebeveyn/alt yapıyı koruyan bir kodum var. Böyle bir yapıda, bir çocuğun bir ebeveyne ve bir ebeveynin bir çocuğa yöneldiği yuvarlak referanslar alıyorum. Onlar için endişelenmeli miyim? Python 2,5 kullanıyorum.Python'daki dairesel referanslar konusunda endişelenmeli miyim?

Çöp toplanmayacakları ve uygulama sonunda tüm belleği tüketeceklerinden endişe duyuyorum.

cevap

25

"Endişe" yersiz olduğunu, ancak programınız yavaş olduğu ortaya çıkarsa, beklenenden daha fazla bellek tüketir veya açıklanamayan garip var duraksamalar, sebebi gerçekten bu çöp referans döngülerinde olması muhtemeldir - "normal" (asiklik) referans grafiğinden farklı bir prosedürle toplanan çöpler olmalı ve bu toplama zaman zaman ve çok fazla zamanınız varsa yavaş olabilir Bu döngülere bağlanmış nesnelerin (döngü içindeki bir nesne __del__ özel yönteme sahipse, döngüsel çöp toplama da engellenir).

Referans döngüleri, programınızın doğruluğunu etkilemez, ancak performans ve/veya ayak izini etkileyebilir.

İstenmeyen başvurular döngüsünü kaldırmak istediğinizde, Python'un standart kitaplığındaki weakref modülünü sıklıkla kullanabilirsiniz.

Döngüsel çöp toplama hakkında daha fazla doğrudan kontrol uygulamak (veya hata ayıklama işlemini gerçekleştirmek için) yapmak istediğinizde, Python'un standart kitaplığındaki gc modülünü kullanın.

+0

Plus 1. Nesnelerin yıkıcıları yan etkilere sahipse, döngüsel referanslar (ve işler yıkıldığında) biraz daha dikkatli düşünebilirsiniz. – speedplane

9

Python çevrimi algılayacak ve dış referans olmadığında belleği serbest bırakacaktır.

+0

tabii varsayarsak hiçbir '__del__' yöntem vardır: Ancak, bu daha sonraki durumda sorun zayıf yöntemlerini başvuramaz olmasıdır. Orada normalde olmamalı ama asla bilemezsin. Bir süreliğine, 'collections.OrderedDict' bile bir sebepten dolayı vardı. – Antimony

15

Deneysel: İyisin:

import itertools 

for i in itertools.count(): 
    a = {} 
    b = {"a":a} 
    a["b"] = b 

O sürekli RAM 3.6   MB kullanarak kalır.

+2

Serin! O zaman ben güvendeyim. :) – bodacydo

+0

Hangi uygulamayı kullandınız? –

+0

@SargeBorsch CPython 2. bir şey. Tüm önemli uygulamaların aynı şekilde davranacağını hayal ediyorum. – cobbal

5

Dairesel referanslar yapılması normal bir şeydir, bu yüzden onlar hakkında endişelenmek için bir neden göremiyorum. Birçok ağaç algoritması, her bir düğümün, çocuklarına ve ailesine olan bağlantılarını gerektirir. Aynı zamanda iki kez birbirine bağlı bir liste gibi bir şey uygulamak zorundalar.

+0

Teşekkürler Colin. "Normal bir şey" olduklarını bilmiyordum. Bana çok özel görünüyorlardı. Ama şimdi başka türlü öğrendim. :) – bodacydo

+0

Ayrıca, onlar açıkça grafikler için gereklidir. – Antimony

3

Endişelenmen gerektiğini düşünmüyorum. Aşağıdaki programı deneyin ve tüm bellek tüketmek değil göreceksiniz:

while True: 
    a=range(100) 
    b=range(100) 
    a.append(b) 
    b.append(a) 
    a.append(a) 
    b.append(b) 
+0

Bu test kodunu yazdığınız için teşekkürler. Düşünmedim. – bodacydo

+0

"extend (b)" demek değil mi? – richizy

+4

@richizy Demek istediğim, çünkü referansı a ve b'ye kaydetmek istiyorum çünkü a ve b değerlerini değil. Bu şekilde dairesel referans gerçekleşecektir. '__del__' hakkında not için – douglaz

1

Bir değişkendeki listelerdeki yöntemlere başvurularla ilgili bir sorun var gibi görünüyor. İşte iki örnek. İlki __del__'u aramaz. Zayıf olan ikinci, __del__ için uygun. http://docs.python.org/2/library/weakref.html

import sys, weakref 

class One(): 
    def __init__(self): 
     self.counters = [ self.count ] 
    def __del__(self): 
     print("__del__ called") 
    def count(self): 
     print(sys.getrefcount(self)) 


sys.getrefcount(One) 
one = One() 
sys.getrefcount(One) 
del one 
sys.getrefcount(One) 


class Two(): 
    def __init__(self): 
     self.counters = [ weakref.ref(self.count) ] 
    def __del__(self): 
     print("__del__ called") 
    def count(self): 
     print(sys.getrefcount(self)) 


sys.getrefcount(Two) 
two = Two() 
sys.getrefcount(Two) 
del two 
sys.getrefcount(Two)