2

スレッド化された応答ハンドラーを生成するサーバー サブクラスがあり、ハンドラーはアプリケーション スレッドを開始します。ObjGraphを使用する場合を除いて、すべてが順調に進んでいます (実行中のアプリケーション スレッドの数が正しいことがわかります (私は負荷テストを行っており、35 個のアプリケーション インスタンスを実行し続けるように調整しています)。

objgraph.typestats()を呼び出すと、(GC に従って) 現在インタープリター内に存在する各オブジェクトのインスタンス数の内訳が提供されます。メモリ リークの出力を見ると、700 個のロガー インスタンスが見つかりました。これは、サーバーによって生成された応答ハンドラーの総数です。

アプリケーション スレッドが run() メソッドを終了するときに logger.removehandler(memoryhandler) と logger.removehandler(filehandler) を呼び出して、ロガー インスタンスへの参照が残っていないことを確認しました。また、ロガー インスタンスはアプリケーション スレッド内で完全に分離されています。 (それへの外部参照はありません)。これらのロガー インスタンスを排除する最後の手段として、run() の最後のステートメントは del self.logger です。

init() でロガーを取得するために、適切な大きさの乱数を指定して名前を付け、ファイル アクセスで区別できるようにします。ログ ファイル名の一部として同じ大きな数を使用して、アプリケーション ログの衝突を回避します。

要するに、GC によって追跡される 700 のロガー インスタンスがありますが、アクティブなスレッドは 35 しかありません。これらのロガーを強制終了するにはどうすればよいですか? より面倒なエンジニアのソリューションは、ロガーのプールを作成し、アプリケーション スレッドの存続期間中 1 つだけを取得することですが、GC が単純にこれを自動的に処理する必要がある場合に、維持するコードがさらに作成されます。

4

2 に答える 2

1

潜在的に無制限の数のロガーを作成しないでください。これは良い習慣ではありません。ここに記載されているように、状況依存の情報をログに取り込む方法は他にもあります

また、ロガーをインスタンス属性として持つ必要はありません。ロガーはシングルトンであるため、どこからでも特定のロガーを名前で取得できます。推奨される方法は、次を使用してモジュール レベルでロガーに名前を付けることです。

logger = logging.getLogger(__name__)

ほとんどのシナリオではこれで十分です。

あなたの質問からは、ハンドラーとロガーが同じものではないことを理解しているかどうかわかりません。たとえば、removeHandler 呼び出しについて話します (参照カウントがゼロになるため、ハンドラー インスタンスを解放するのに役立つかもしれませんが、'そうすることでロガーインスタンスを解放しないでください)。

一般に、ロガーは、関心のあるイベントを生成するアプリケーションの部分にちなんで命名されます。

たとえば、各スレッドで異なるファイルに書き込みたい場合は、毎回新しいファイル名を作成し、作業が完了してスレッドが終了しようとしているときにハンドラーを閉じることができます (そのクローズはハンドラー リソースを解放するために重要です)。または、ログ出力に含まれるスレッド ID またはその他の識別子を使用してすべてを 1 つのファイルに記録し、ログ ファイルで後処理を使用することもできます。

于 2011-06-17T17:15:06.013 に答える
0

logging.Logger() を使用しているときに同じメモリ リークが発生しました。次のように、ロガーが役に立たない場合は、ハンドラー fd を手動で閉じようとする場合があります。

for handler in logger.handlers:
    handler.close()
于 2014-04-01T08:12:25.733 に答える