2011-09-06 12 views
7

我々は、次のようないくつかの定型を持つクラスのコードの多くを持っている:静的最終変数初期化子からLoggerを取得するのは効率的ですか?

private static Logger logger = null; 

private static Logger getLogger() { 
    if (logger == null) { 
    logger = Logger.getLogger(MyClass.class); 
    } 
    return logger; 
} 

アイデアは、クラスがロガーにデバッグものをログに記録できることです。何かをログに記録する必要がある最初のコードは、getLogger()を呼び出し、ロガーを存在させます。

このパターンについて私が気に入らないことがいくつかあります。まず、シングルトンのgetLogger()は同期化されておらず、同期していますが、正しい理由は何もないため、後続の各コールに負担がかかります。

私は本当にただこれにそれを凝縮することができるようにしたい:

private static final Logger logger = Logger.getLogger(MyClass.class); 

その後、私はちょうど直接ロガーを参照することができ、さらにはシングルトンゲッターと気にしません。

私が恐れる問題は、これを行うことで、ロガーが呼び出されなくてもクラスがロードされたときにロガーが作成されることです。私は10,000以上の奇数のクラスをすべてgetLogger()を呼び出すので、実際にここで作成するLoggerのインスタンスはいくつですか?私のlog4jプロパティにいくつかのアペンダーが含まれている場合、私は同じロガーを何度も繰り返し参照していますか、またはこれらのものを10,000個作成していますか?

+4

スレッド安全性を考慮してください! –

+0

スレッドの安全性を検討しています。だから、私は壊れたシングルトンを取り除き、本質的にスレッドセーフなクラスローダーに頼っています。 – locka

+0

AFAICS問題は、2つのスレッドが同時にロガーをフェッチしようとすると、2つの 'Logger'インスタンスが作成されるということです。 –

答えて

2

デフォルトのLog4j構成(デフォルトのLoggerRepository、DefaultCategoryFactoryなど)を使用すると、10,000個のLoggerインスタンスが作成されます。彼らはどれくらいのメモリを消費していますか?神とあなたのプロファイラ以外の誰もこれを知らない。 (そして私の推測では、後者の人だけがそれをあなたに伝えます)。

メモリフットプリントは、ご使用の環境のためにあまりにも多く、このような静的な内部クラスにロガーの初期化を移動したい場合:

static class LoggerHolder { 
    static Logger logger = Logger.getLogger(MyClass.class); 
} 

private static Logger getLogger() { 
    return LoggerHolder.logger; 
} 

Loggerのインスタンスのみ、最初のgetLoggerの呼び出しで作成されますこの方法。 (この技法はIODH(Initialization On Demand Holder)として知られていますが、スレッドセーフで同期オーバーヘッドはゼロです)。

私はあなたに少しの提案をしてもいいですか? Log4JをSLF4J + Logbackライブラリの組み合わせに置き換えることを検討してください。彼らは非常に同じ著者によって書かれ、 "a successor to the popular log4j project, picking up where log4j leaves off"と記述されています。 this SO threadで詳しく読むことができます。

+0

私のロガーインスタンスを保持するために10,000の余分なクラスを持っているなら、1ポイント、グレードアップしてください。PermGenスペースに圧力をかける危険はありませんか? – locka

+0

@lockaはい、10000の追加クラスがPermGen空間でいくらかの領域を占有します。しかし、再びメモリプロファイラだけが実際の数値を教えてくれるはずです...私は、Logger用のIODHを持つわずか10,000ダミークラスのサンプルプロジェクトを作成しました。そして、それらのすべてのためにgetLogger()を1つずつ呼び出します。私のOSX JVMはPermGenのために〜50Mbを消費しました。少量ではなく、重要なものではありません。 (getLoggerを呼び出さなければ、内部クラスはロードされません)。 – Idolon

2

クラスが実際に初期化された場合、つまりの場合にのみオブジェクトを作成します。その時点で、クラスあたりの単一のオブジェクトの小さなオーバーヘッドは本当にそれほど重要ですか?

最も簡単な答え:両方の方法で試してみて、パフォーマンス/メモリ/その他に大きな違いがあるかどうかを確認してください。できるとは思っていますが、可能であれば、 データに基づいて、最も適切な行動方針は何か。

+0

テストのために、パフォーマンス/メモリの違いを比較する際に表示される、各クラスのロガー変数を使用することをお勧めします。 – medopal

1

ロードするクラスごとに別々のロガーインスタンスを作成していますが、メモリ使用量が少ないと思います。 Log4Jは広範囲に最適化されていることが知られており、メモリ使用量については考えていないと思われます。

全体的に、あなたが10Kのクラスを持っていれば、あなたのアプリは膨大です。メモリ消費量に大きな違いがないことは間違いありません。しかし、もちろん、あなたの具体的な環境で両方を測定するのはもちろんです。

0

スタティック変数は、すべてのインスタンスで一度に同じオブジェクトが初期化されます。あなたはシングルトンパターンのためのその方法を実際には必要としません。private static Logger getLogger()

ちょうどそれは怠惰に読み込まれますが、それは大きな利益だとは思わないです。本当に少量の時間で、オブジェクトの貧弱な部分が作成され、破壊されます。

0

通常の方法(静的な最終フィールド)はPMDによっておこなわれます。ロガーを使用している場合は、使用される可能性が高いため、遅延を初期化することでメモリの面では何も得られません。

しかし、これは定数なので、LOGGERを大文字にします。

0

OPの非同期getLogger()メソッドはokですが、ince Loggerはスレッドセーフです。 Loggerは変更可能で、同時に使用するように設計されているため、追加の同期を行わなくてもその参照を安全に公開できない場合は驚きます。 。

ただし、メモリ使用の心配は必要ありません。各クラスの余分なオブジェクトをオーバーヘッドにする必要はありません(Loggerオブジェクトはあまりにも巨大ではないことを願って)

関連する問題