13

私は、sys.stdin を介して処理するために何百万ものグロブを渡すカスタム ファイル システム クローラーを作成しています。スクリプトを実行すると、時間の経過とともにメモリ使用量が大幅に増加し、すべてが実質的に停止することがわかりました。問題を示す最小限のケースを以下に書きました。私は何か間違ったことをしていますか、それとも Python / glob モジュールでバグを見つけましたか? (私はpython 2.5.2を使用しています)。


#!/usr/bin/env python
import glob
import sys
import gc

previous_num_objects = 0

for count, line in enumerate(sys.stdin):
   glob_result = glob.glob(line.rstrip('\n'))
   current_num_objects = len(gc.get_objects())
   new_objects = current_num_objects - previous_num_objects

   print "(%d) This: %d, New: %d, Garbage: %d, Collection Counts: %s"\
 % (count, current_num_objects, new_objects, len(gc.garbage), gc.get_count())
   previous_num_objects = current_num_objects

出力は次のようになります。

(0) This: 4042, New: 4042, Python Garbage: 0, Python Collection Counts: (660, 5, 0)
(1) This: 4061, New: 19, Python Garbage: 0, Python Collection Counts: (90, 6, 0)
(2) This: 4064, New: 3, Python Garbage: 0, Python Collection Counts: (127, 6, 0)
(3) This: 4067, New: 3, Python Garbage: 0, Python Collection Counts: (130, 6, 0)
(4) This: 4070, New: 3, Python Garbage: 0, Python Collection Counts: (133, 6, 0)
(5) This: 4073, New: 3, Python Garbage: 0, Python Collection Counts: (136, 6, 0)
(6) This: 4076, New: 3, Python Garbage: 0, Python Collection Counts: (139, 6, 0)
(7) This: 4079, New: 3, Python Garbage: 0, Python Collection Counts: (142, 6, 0)
(8) This: 4082, New: 3, Python Garbage: 0, Python Collection Counts: (145, 6, 0)
(9) This: 4085, New: 3, Python Garbage: 0, Python Collection Counts: (148, 6, 0)

100 回の反復ごとに 100 個のオブジェクトが解放されるため、len(gc.get_objects()100 回の反復ごとに 200 ずつ増加します。len(gc.garbage)0 から変化することはありません。第 2 世代のコレクション カウントはゆっくりと増加しますが、0 番目と 1 番目のカウントは上下します。

4

2 に答える 2

7

これを fnmatch モジュールまで追跡しました。glob.glob は fnmatch を呼び出して実際にグロビングを実行します。fnmatch には、クリアされることのない正規表現のキャッシュがあります。したがって、この使用法では、キャッシュは継続的に増加し、チェックされませんでした。fnmatch ライブラリに対してバグを報告しました [1]。

[1]: http://bugs.python.org/issue7846 Python のバグ

于 2010-02-03T16:01:09.353 に答える
2

私のシステムで実際のリークを再現することはできませんが、「100 回の反復ごとに 100 個のオブジェクトが解放される」のは、コンパイルされた正規表現のキャッシュに ( glob モジュールを介して) ヒットしていると思います。re.py をのぞく_MAXCACHEと、デフォルトが 100 に設定されていることがわかります。デフォルトでは、それをヒットすると、キャッシュ全体が吹き飛ばされます(_compile)。電話をかけるre.purge()前にgc電話すると、おそらくその効果がなくなることがわかります。

(ここでは、キャッシュが gc の結果に影響を与えていることを確認することのみを提案していることに注意re.purge()してください。実際のコードでそれを行う必要はありません。)

ただし、大規模なメモリ増加の問題が修正されるとは思えません。

于 2010-02-02T12:55:47.637 に答える