26

psycopg2 を使用して、postgres データベースに対して Python スクリプトで大きなクエリを実行しています (バージョン 2.5 にアップグレードしました)。クエリが終了したら、カーソルと接続を閉じ、さらに gc を実行しますが、プロセスは依然として大量のメモリ (正確には 7.3 GB) を消費します。クリーンアップ手順がありませんか?

import psycopg2
conn = psycopg2.connect("dbname='dbname' user='user' host='host'")
cursor = conn.cursor()
cursor.execute("""large query""")
rows = cursor.fetchall()
del rows
cursor.close()
conn.close()
import gc
gc.collect()
4

3 に答える 3

11

より良い解決策については、@joeblog による次の回答を参照してください。


まず、最初からすべての RAM を必要とするべきではありません。ここですべきことは、結果セットのチャンクをフェッチすることです。しないでくださいfetchall()。代わりに、より効率的なcursor.fetchmany方法を使用してください。psycopg2 のドキュメントを参照してください。

ここで、解放されない理由と、その用語を形式的に正しく使用することでメモリ リークではない理由を説明します。

ほとんどのプロセスは、解放されたときにメモリを OS に解放しません。プログラムの他の場所で再利用できるようにするだけです。

プログラムがメモリに散らばっている残りのオブジェクトを圧縮できる場合にのみ、メモリを OS に解放できます。これは、間接ハンドル参照が使用されている場合にのみ可能です。そうしないと、オブジェクトを移動すると、オブジェクトへの既存のポインターが無効になるためです。間接参照はかなり非効率的です。特に最近の CPU では、ポインターを追い回すとパフォーマンスが大幅に低下します。

プログラムで特別な注意を払わない限り、通常、割り当てられたメモリの大きなチャンクがbrk()、いくつかの小さな断片がまだ使用されている状態でランドに到達するということが起こります。

OS は、プログラムがこのメモリをまだ使用中であると見なしているかどうかを判断できないため、単に要求することはできません。プログラムはメモリにアクセスする傾向がないため、通常、OS は時間の経過とともにメモリをスワップアウトし、物理メモリを他の用途に解放します。これが、スワップ領域が必要な理由の 1 つです。

メモリを OS に戻すプログラムを作成することは可能ですが、Python でそれができるかどうかはわかりません。

以下も参照してください。

つまり、これは実際にはメモリリークではありません。大量のメモリを使用する何か他のことを行う場合、プロセスはそれほど大きくならないはずです。最後の大きな割り当てから以前に解放されたメモリを再利用します。

于 2013-06-20T01:20:53.313 に答える