を使用したとき、私はクラスCollector
と、このようなThreadLocalScope
ています旧世代メモリが増加ThreadLocalの
Collector {
Collector() {
events = new LinkedList<>();
}
add(Event e) {
events.add(e);
}
flush() {
LinkedList<Event> copy = events;
new Thread(() -> {
for (Event e : copy) {
sendToServer(e);
}
copy.clear();
).start();
events = new LinkedList<>();
}
}
ThreadLocalScope {
public static ThreadLocal<Collector> local = new ThreadLocal<>() {
protected Collector initialValue() {
return new Collector();
}
}
}
Collector
は、単純にイベントを追加し、flush
が呼び出されたときに新しいスレッドでAPIにこれらのイベントを送信します。 Collector
はThreadLocalで初期化されます。
また、(Quartzを使用して)何度も実行されるJobクラスもあります。このすべてが素晴らしい作品のように定義された場合:
Job {
execute() {
for (int i = 0; i < 100,000; i++) {
ThreadLocalScope.get().add(new Event());
}
ThreadLocalScope.get().flush();
}
}
代わりに、私はこのように集電体上に保持する場合は:
Job {
Collector collector;
Job() {
collector = ThreadLocalScope.get();
}
execute() {
for (int i = 0; i < 100,000; i++) {
collector.add(new Event());
}
collector.flush();
}
}
私は旧世代のメモリ使用量が急激に増加し、ストップ世界をガベージコレクションサイクルご覧くださいいつも起こっている。唯一の違いは、毎回ThreadLocalScope.get()
を呼び出すのではなく、Collector
をメンバー変数として追加したことです。
この増加は、イベントが旧世代に移動されていることを意味します。しかし、なぜそれが起こるだろうか? Collector
はすぐにイベントへの参照をすべてクリアします。したがって、GCedでない場合でもイベントは発生しています。
ThreadLocalは、その変数にアクセスできるスレッドが1つだけであることを意味します。したがって、各スレッドには独自の 'Collector'インスタンスがあります。正しい競合条件はありませんか? – dg428
はいクォーツはスレッドを再利用します。しかし、私はjob creationとexecute()が同じスレッド上で動作することを確認しました。私はイベントをクリアするので、次の仕事のためのコレクターの募集は問題ではない – dg428
まだ、私はあなたの問題の根源だと思う。そして、正直言って、スレッドローカルは効率を助けていないし、そのようなスレッドを作成する 'flush()'は大きなパフォーマンスヒットです。 –