上記の最適化では、500 ユーザーごとにいくつかの計算が実行され、結果がディスク ファイルに記録されます。私は当初、これを行うことで、これらの結果がディスク ファイルに保存され、メモリを占有し続けることはないと考えていました。しかし、実際には、Python の大きな落とし穴は、Python がこれらのメモリを自動的にクリーンアップしないことです。これは独自の実装によって決まります。具体的な理由を説明した記事がインターネット上にたくさんあるので、ここではコピーしません。
この記事では、Python にメモリが解放されない現象があることを説明するために、著者による実験的なスクリプトを掲載します。さらに、最初に del を実行し、次に明示的に gc.collect() を呼び出すという解決策も提案します。スクリプトと詳細 効果は以下の通りです。
実験環境 1: Win 7、Python 2.7
from time import sleep, time import gc def mem(way=1): print time() for i in range(10000000): if way == 1: pass else: # way 2, 3 del i print time() if way == 1 or way == 2: pass else: # way 3 gc.collect() print time() if __name__ == "__main__": print "Test way 1: just pass" mem(way=1) sleep(20) print "Test way 2: just del" mem(way=2) sleep(20) print "Test way 3: del, and then gc.collect()" mem(way=3) sleep(20)
実行結果は次のとおりです:
Test way 1: just pass 1426688589.47 1426688590.25 1426688590.25 Test way 2: just del 1426688610.25 1426688611.05 1426688611.05 Test way 3: del, and then gc.collect() 1426688631.05 1426688631.85 1426688631.95
方法 1 と方法 2 では、結果はまったく同じです。プログラムのピークメモリ消費量は 326772KB です。 20 秒間のスリープ時のリアルタイム メモリ消費量は 244820KB です。方法 3 の場合、プログラムのピーク メモリ消費量は上記と同じですが、スリープ中のリアルタイム メモリ消費量はわずか 6336KB です。
実験環境 2: Ubuntu 14.10、Python 2.7.3実行結果:
Test way 1: just pass 1426689577.46 1426689579.41 1426689579.41 Test way 2: just del 1426689599.43 1426689601.1 1426689601.1 Test way 3: del, and then gc.collect() 1426689621.12 1426689622.8 1426689623.11
ubuntu@my_machine:~$ ps -aux | grep test_mem Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html ubuntu 9122 10.0 6.0 270916 245564 pts/1 S+ 14:39 0:03 python test_mem.py ubuntu 9134 0.0 0.0 8104 924 pts/2 S+ 14:40 0:00 grep --color=auto test_mem ubuntu@my_machine:~$ ps -aux | grep test_mem Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html ubuntu 9122 10.0 6.0 270916 245564 pts/1 S+ 14:39 0:03 python test_mem.py ubuntu 9134 0.0 0.0 8104 924 pts/2 S+ 14:40 0:00 grep --color=auto test_mem ubuntu@my_machine:~$ ps -aux | grep test_mem Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html ubuntu 9122 11.6 0.1 30956 5608 pts/1 S+ 14:39 0:05 python test_mem.py
結論:
上記は、del が呼び出されたとき、Python は実際にはメモリを解放せず、メモリをメモリに配置し続けることを示しています。メモリ プール内に配置します。メモリは、gc.collect() が明示的に呼び出された場合にのみ解放されます。
さらに:
実際には、前のブログのスクリプトに戻って gc.collect() を導入し、メモリ消費を監視する監視スクリプトを作成します:
while ((1)); do ps -aux | sort -n -k5,6 | grep my_script; free; sleep 5; done
結果は次のようになります: メモリは500 回ごとに変更しない ユーザーは一連の実行後に再開しますが、残り約 70MB になるまで消費を続け、その後 gc が機能するように見えます。この環境では、マシンはクラウド インスタンスを使用しており、合計メモリは 2G、使用可能なメモリは約 1G です。このスクリプトの一般的なメモリ消費量は 900M ~ 1G です。つまり、このスクリプトの場合、gc はすぐには有効になりませんが、システムの使用可能なメモリが 1 ~ 1.2G からわずか約 70M に低下すると、gc が有効になり始めます。これは確かに奇妙です。スクリプトが Thread で gc.collect() を使用するという事実と関係があるのか、それとも gc の関数がそもそも制御できないのかはわかりません。著者はまだ関連する実験を行っていないため、次回のブログで引き続き議論する可能性があります。
ただし、gc.collect() を使用しない場合、元のスクリプトがシステム メモリを使い果たして強制終了されることは確かです。これは syslog から明らかです。
以上がPython メモリを手動で解放する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。