2015-03-25 34 views
1

我想刪除所有引用一個內存位置的對象。如果我不知道他們的全名,該怎麼辦?如何刪除在Python中引用對象的內存位置?

class Foo(object): 
    pass 


class Bar(object): 
    pass 

a = Foo() 
b = a 
c = Bar() 
c.a_ref = a 
c.b_ref = b 

for item in a, b, c.a_ref, c.b_ref: 
    print(id(item)) 

""" Out: 
140035270075472 
140035270075472 
140035270075472 
140035270075472 
""" 

UPD:

確定。我想刪除linkport1.link,不用擔心所有連接到它的其他端口(port2.link),它們也不得不消失。

class LINK(object): 
    pass 


class PORT(object): 

    def __init__(self, link=None): 
     self.link = link 

    def __repr__(self): 
     return str(id(self.link)) 

link = LINK() 

port1 = PORT() 
port2 = PORT() 
port1.link = port2.link = link 

print(id(link), port1, port2) 
# (140586778512720, 140586778512720, 140586778512720) 
del link 
print(port1, port2) 
# (140586778512720, 140586778512720) 
# want: (None, None) ??? 
+1

爲什麼?你真正的問題是什麼? – 2015-03-25 07:35:52

+0

我是一個小更新的例子,也許它可以做不同,但我認爲刪除內存位置的想法是邏輯 – uralbash 2015-03-25 08:10:55

+0

如果我的答案有幫助,不要忘記接受它。謝謝! – 2015-03-26 13:42:47

回答

1

weakref模塊。它保持對對象的引用,而不會阻止它被垃圾收集,如果其所有強引用都被刪除。例如:

import weakref 

class LINK(object): 
    pass 

class PORT(object): 

    def __init__(self, link=None): 
     if link is not None: 
      self.link = weakref.ref(link) 
     else: 
      self.link = None 

    def __repr__(self): 
     if self.link is None: 
      return 'None' 
     o = self.link() 
     return 'None' if o is None else str(id(o)) 

link = LINK() 

port1 = PORT() 
port2 = PORT() 
port1.link = port2.link = weakref.ref(link) 

print(id(link), port1, port2) 
del link 
print(port1, port2) 

輸出:

70741240 70741240 70741240 
None None 

注意,你可能還是要打電話gc.collect()在某些情況下,弱引用報告None之前。

+0

謝謝,這是我的預期。但其他答案對我也很有用! – uralbash 2015-03-30 10:38:18

1

你不能明確地釋放內存。你需要做的是確保你不保留對象的引用。然後他們將被垃圾收集,釋放內存。 順便說一下,你可以打電話gc.collect()強制執行gc操作。

UPDATE:

您無法通過只刪除其引用的一個刪除一個對象的所有引用,因爲你不還有誰仍然在使用這個對象知道。如果是這樣,還會有另一個問題,如何防止他人刪除我的對象而不承認我。

我認爲你的問題的最佳解決辦法是分別刪除屬性鏈接。

del link 
del port1.link 
del port2.link 

然後刪除後得到無,你應該這樣做:

... 
def __repr__(self): 
     repr_string = getattr(self, 'link', None) 
     return str(id(self.link)) if repr_string else None 
... 
+0

請參閱UPD:''gc.collect''沒有解決我的問題 – uralbash 2015-03-25 08:13:06

+0

@uralbash檢查我的更新 – 2015-03-25 08:32:18

+0

是的,但是如何獲取所有鏈接的對象,如果它們可能會更改? – uralbash 2015-03-25 09:09:38

3

你不能在Python中顯式釋放內存。垃圾收集器負責爲你做這件事。

你可以做的是保證所有對你的對象的引用都被清除。垃圾收集器與時代(如e1,e2和e3)一起工作,只有e3中的對象將在下一次迭代中清理。

如果沒有對象的引用,對象只能從epoch eX到eY(其中Y> X)。所以你的對象從e1開始;如果你「清除」了所有的引用,在垃圾回收器的下一次迭代中,它們將被移動到e2;在下一個他們將被移動到e3,最後內存將被釋放。

您可以更改垃圾收集器被調用的週期性,但我不會建議這樣做。或者您可以使用gc.collect()強制垃圾回收器的調用,但正如我所說的,您的對象必須在清理之前先通過所有時代(這就是爲什麼gc.collector()的調用不適合您的原因)。只是爲了澄清,一旦達到閾值(由gc跟蹤的內存中的對象的數量),就會調用垃圾收集器。

如果你想在Python中診斷內存泄漏,你也可以使用objgraph庫,這非常好。它用對象之間的所有鏈接和引用構建圖形,並讓您識別週期。當您認爲所有引用都被清除時,循環是垃圾收集器不會釋放對象的主要原因。這是一個很好的教程http://chase-seibert.github.io/blog/2013/08/03/diagnosing-memory-leaks-python.html

1

對我來說,你真正的問題聽起來像你有一個圖,其中PORT s是節點,LINK s是邊緣。而且您的要求是,當您刪除邊緣時,邊緣連接的兩個節點也應該被刪除。這可以通過覆蓋節點的__del__方法來顯式完成,以便刪除它將刪除連接的邊。

Python將「內存」抽象化,並使用id爲您提供內存位置(這實際上是CPython的實現細節),這是做這件事的一種片狀方式。

相關問題