これは私にもまったく意味がありません。私はこれがどのように/なぜ起こるのかを理解したかったのです。(これもこのように機能するはずだと思いました!)ファイルを小さくして、自分のマシンに複製しました。
ここで2つの個別の問題が発生しました
- Pythonがファイルをメモリに読み取るのはなぜですか(怠惰な行の読み取りでは、そうではありません-正しいですか?)
- Pythonがシステムにメモリを解放しないのはなぜですか
私はPythonの内部についてまったく知識がないので、Web検索をたくさん行いました。これらはすべて、完全にマークから外れている可能性があります。(私はもうほとんど開発していません。過去数年間、テクノロジーのビジネス側にいます)
怠惰な行の読み取り...
私は周りを見回してこの投稿を見つけました-
http://www.peterbe.com/plog/blogitem-040312-1
それはずっと以前のバージョンのpythonからのものですが、この行は私に共鳴しました:
readlines()はファイル全体を一度に読み込み、行ごとに分割します。
それから私はこれも古い、effbotの投稿を見ました:
http://effbot.org/zone/readline-performance.htm
重要なポイントはこれでした:
たとえば、十分なメモリがある場合は、readlinesメソッドを使用して、ファイル全体をメモリに丸呑みすることができます。
この:
Python 2.2以降では、ファイルオブジェクト自体をループできます。これは、内部のreadlines(N)とほとんど同じように機能しますが、見た目ははるかに優れています。
xreadlinesのpythonsドキュメントを見る[ http://docs.python.org/library/stdtypes.html?highlight=readline#file.xreadlines ]:
このメソッドは、iter(f)と同じものを返します。バージョン2.3以降非推奨:代わりにファイル内の行に使用してください。
たぶん、なんらかの丸呑みが起こっているのではないかと思いました。
したがって、readlines[ http://docs.python.org/library/stdtypes.html?highlight=readline#file.readlines ]..を見ると
readline()を使用してEOFまで読み取り、読み取った行を含むリストを返します。
それがここで起こっていることのようです。
しかし、readlineは私たちが望んでいたもののように見えました[ http://docs.python.org/library/stdtypes.html?highlight=readline#file.readline ]
ファイルから1行全体を読み取ります
だから私はこれをreadlineに切り替えようとしましたが、プロセスは40MBを超えることはありませんでした(以前はログファイルのサイズである200MBに成長していました)
accounts = dict()
data= open(filename)
for line in data.readline():
info = line.split("LOG:")
if len(info) == 2 :
( a , b ) = info
try:
accounts[a].add(True)
except KeyError:
accounts[a] = set()
accounts[a].add(True)
私の推測では、私たちは本当に怠惰ではありませんfor x in data
-構成を使用してファイルを読んでいます-すべてのドキュメントとstackoverflowコメントは私たちが怠惰であることを示唆していますが。 readline()
私にとってはかなり少ないメモリをrealdlines
消費し、ほぼ同じ量のメモリを消費しましたfor line in data
メモリを解放する
メモリを解放するという点では、Pythonの内部についてはあまり詳しくありませんが、mod_perlで作業したときのことを思い出します... 500MBのファイルを開くと、そのapacheの子はそのサイズに成長しました。メモリを解放した場合、その子内でのみ解放されます。ガベージコレクションされたメモリは、プロセスが終了するまでOSに戻されませんでした。
だから私はそのアイデアをざっと見て、これが起こっているかもしれないことを示唆するいくつかのリンクを見つけました:
http://effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm
大きなオブジェクトを作成して再度削除すると、Pythonがメモリを解放した可能性がありますが、関連するメモリアロケータは必ずしもメモリをオペレーティングシステムに返すとは限らないため、Pythonプロセスがより多くの仮想メモリを使用しているように見える場合があります実際に使用するよりも。
それはちょっと古いもので、その後pythonにランダムな(受け入れられた)パッチがたくさん見つかりました。これは、動作が変更され、メモリをOSに戻すことができることを示唆しています(これらのパッチのほとんどが送信され、明らかに承認された2005年現在)。
それから私はこの投稿http://objectmix.com/python/17293-python-memory-handling.htmlを見つけました-そしてコメント#4に注意してください
"" "-パッチ#1123430:Pythonのスモールオブジェクトアロケータは、アリーナfree()
内のすべてのメモリが再び使用されなくなったときに、アリーナをシステムに返すようになりました。Python2.5より前は、アリーナ(256KBのメモリチャンク)が解放されることはありませんでした。一部のアプリケーションでは、仮想メモリサイズの低下、特に、一時的に多数の小さなオブジェクトを使用する長時間実行アプリケーション。PythonがアリーナをプラットフォームCに返す場合free()
、プラットフォームCライブラリが次に、そのメモリをオペレーティングシステムに戻します。パッチの効果は、それを不可能にすることをやめることであり、テストでは、少なくともMicrosoftCおよびgccベースのシステムで効果的であるように見えます。ハードワークと忍耐力を提供してくれたEvanJonesに感謝します。 。
したがって、Linuxで2.4を使用すると(テストしたとおり)、収集される多数の小さなオブジェクトに関して、使用済みのメモリが常に元に戻るとは限りません。
したがって、(私が思うに)f.read()とf.readlines()を実行することの違いは、前者はファイル全体を1つの大きな文字列オブジェクト(つまり、小さなオブジェクトではない)として読み取るのに対し、後者は各行がPythonオブジェクトである行のリスト。
'for line in data:'構文が本質的にラッピングreadlines
であり、そうでない場合readline
、おそらくこれはそれと関係がありますか?おそらく、3GBのオブジェクトが1つあるという問題ではなく、数百万の30kのオブジェクトがあるという問題です。