を使用するときは、完了したときにThreadLocal
常に呼び出す必要がありますか、古い値を使用するときに、とにかく置き換えられるので冗長ですか?remove()
set
remove
7 に答える
ThreadLocal
とがMap
あるため、それを使用していたスレッドの値を削除しないと、メモリ リークが発生しますcurrentThread
。value
ThreadLocalクラスはThreadLocal.Values localValues で定義され たThreadクラスから値を設定するため、常にremoveを呼び出す必要があります。これにより、Thread および関連オブジェクトの参照も保持されます。
のソースコードからThreadLocal
値は null に設定され、基になるエントリは引き続き存在します。
set
常に古い値を置き換えます。
これは本当です
- Calendar.set() および Date.set()
- BitSet.set()
- リスト.set()
- セッター
削除しないとGCされないということですか?
スレッドが死ぬまで削除されません。remove() を呼び出さないと消えません
これがメモリ リークであるかどうかは、プログラムによって異なります。何らかの理由で必要のない大きなスレッドローカルオブジェクトを使用して、多くのスレッドを作成する必要があります。たとえば、1 KB のオブジェクトを持つ 1000 のスレッドは最大 1 MB を浪費する可能性がありますが、この種のことを行う場合、これは設計上の問題を示唆しています。
メモリリークが発生する唯一の場所は.
for (int i = 0; ; i++) {
// don't subclass Thread.
new Thread() {
// this is somewhat pointless as you are defining a ThreadLocal per thread.
final ThreadLocal<Object> tlObject = new ThreadLocal<Object>() {
};
public void run() {
tlObject.set(new byte[8 * 1024 * 1024]);
}
}.start();
Thread.sleep(1);
if (i % 1000 == 0) {
System.gc();
System.out.println(i);
}
}
-verbosegc
プリント付き。
[Full GC 213548K->49484K(3832192K), 0.0334194 secs]
39000
[GC 2786060K->82412K(3836864K), 0.0132035 secs]
[GC 2815569K->107052K(3836544K), 0.0212252 secs]
[GC 2836162K->131628K(3837824K), 0.0199268 secs]
[GC 2867613K->156204K(3837568K), 0.0209828 secs]
[GC 2886894K->180780K(3838272K), 0.0191244 secs]
[GC 2911942K->205356K(3838080K), 0.0187482 secs]
[GC 421535K->229932K(3838208K), 0.0192605 secs]
[Full GC 229932K->49484K(3838208K), 0.0344509 secs]
40000
注: フル GC 後のサイズは同じです49484K
上記の場合、ThreadLocal を参照する Thread を参照する ThreadLocal があります。ただし、スレッドが死んでいるため、メモリ リークは発生しません。これは、A -> B および B -> A の場合に関連オブジェクトになるためです。
上記の例を数分間ループで実行したところ、GC レベルはかなり移動しましたが、最小サイズはまだ小さかったです。
set
: このスレッドローカル変数の現在のスレッドのコピーを指定された値に設定します。
つまり、その記憶場所にあったものはすべて、通過したものによって上書きされますset
あなたがしようとしている変数がスレッドの次の実行にremove
常にある場合set
、それを削除することについて心配する必要はありません。set
その値を上書きします。
ただし、その変数を特定の状況でのみ設定している場合 (たとえば、特定の種類の要求のみを処理する場合)、それを削除すると便利な場合があります。プール。
簡単に説明します。なんらかの理由で ThreadLocal を拡張する場合は、 を使用しますremove()
。バニラで ThreadLocal を使用しますset(null)
。基本的ThreadLocal.remove()
に、拡張されたThreadLocal で使用しないと、メモリ リークが発生する可能性があります (ClassLoader の可能性が最も高い)。
理由の詳細が必要な場合は、コメントを投稿してください。