0

いくつかのカスタム クラスと多くの辞書を使用する大量のコードがあります。多くのクラスには、辞書が属性として追加されます。特にループしている場合、クラスと辞書の一部を手動で削除しても、メモリを使いすぎていることがわかりました。

私が恐れているのは、辞書が削除されていることですが、辞書に含まれるオブジェクトは存続しています。メモリ管理を改善するためにコードをリファクタリングする必要がありますが、迅速な解決策として、辞書を再帰的かつ積極的に削除できることを望んでいました。これはどのように達成されますか?

ここに例があります...

def get_lrg():
    return {1: np.zeros((1000,1000,100))}

class H():
    def add_lrg(self):
        fd = get_lrg()
        self.lrg = fd

for cls in ['a', 'b', 'c', 'd']:
    exec('{0} = H()'.format(cls) )
    exec('{0}.add_lrg()'.format(cls) )

del a
del b
del c
del d

また、これでIpythonで遊んでください:

fd = get_lrg()
fd2 = get_lrg()
F = {1: fd, 2: fd2}
F = {}
F = {1: fd, 2: fd2}
del F[1]

del F

Pythonアプリケーションのメモリ使用量を監視します...辞書「F」が削除された後でもメモリを「解放」しているようには見えません(たとえば、オブジェクトへの参照はありません)。私のマシンで見つけたのは、結果が予測できないということです。メモリがフラッシュされているように見えることもあれば、使用されているように見えることもあります。

4

2 に答える 2

6

辞書を削除した後に辞書内のオブジェクトが生きている場合、一部のコードがそれらを参照しているため、それらは生きているはずです。

Python がメモリを処理する方法は 2 つあります。

  1. 参照カウント
  2. マーク アンド スイープ ガベージ コレクタ

ディクショナリを削除すると、問題のオブジェクトへの参照が削除されます。それがそれらのオブジェクトへの最後の参照である場合、それらは自動的に解放されます。

ただし、オブジェクト間のサイクルが存在する場合、外部参照が存在しない場合でも、サイクル内のすべてのオブジェクトが少なくとも 1 つのライブ参照を持つことになるため、参照カウントは十分ではありません。

これが、少し後になりますが、これをクリーンアップするガベージ コレクターも存在する理由です。参照カウントは、参照が 0 に達するとオブジェクトを処理し、ガベージ コレクターは少し後に機能します。

したがって、何も再帰的に削除する必要はありません。辞書への参照を削除するだけで、残りは Python に任せることができます。

SO に関する別の質問があり、もう少し詳しく説明します。なぜ python は gc に参照カウントとマークアンドスイープの両方を使用するのですか? .

これは、次のコードで確認できます。

class X:
  def __del__(this):
    print("deleted")

  def __init__(this):
    print("constructed")

print("before")
x = X()
print("after")
del x
print("done")

これにより、メソッドがステートメント__del__の一部として実行されることがわかります。del x

次に、これがあります:

class X:
  def __del__(this):
    print("deleted")

  def __init__(this):
    print("constructed")

print("before")
x = X()
y = X()
x.y = y
y.x = x
print("after")
del x
del y
print("done")

これは、サイクル (xy相互参照の両方) が異なる方法で処理されることを示しています。

次に、これを辞書に保存しxてから辞書を削除すると、xオブジェクトが辞書と一緒に削除されます。

class X:
  def __del__(this):
    print("deleted")

  def __init__(this):
    print("constructed")

print("before")
d = {"x": X()}
print("after")
del d
print("done")
于 2013-08-09T13:08:39.563 に答える
4

オブジェクトを削除すると、そのオブジェクトへの参照が削除されるだけです。そのオブジェクトの参照カウントが 0 になると、そのオブジェクトが保持している他のオブジェクトへの参照をすべて取得して、メモリから削除されます。

たとえば、辞書にはオブジェクトが含まれていません。それらに含まれているのは、他のオブジェクトへの参照だけです。ディクショナリへの参照をすべて削除すると、ディクショナリは自動的にクリーンアップおよび削除され、その参照もすべて失われます。ディクショナリが参照するすべてのキーまたは値は、参照カウントが 1 ずつ減少します。そして、そのカウントが 0 になると、それらはクリーンアップされます。

したがって、再帰的に何かを削除する必要はありません。オブジェクトが参照されなくなった場合、それらは自動的にクリーンアップされます。

Python がオブジェクトを解放しても、プロセスのメモリ使用量は必ずしも従わないことに注意してください。オペレーティング システムは、プロセスに割り当てられたメモリを維持して、メモリ チャーンを減らすことができます。プロセスは再びメモリ使用量を増やす必要があるかもしれませんが、他の場所でメモリが緊急に必要でない限り、割り当てはしばらくの間保持されます。

于 2013-08-09T13:06:25.657 に答える