21

を使用するときは、完了したときにThreadLocal常に呼び出す必要がありますか、古い値を使用するときに、とにかく置き換えられるので冗長ですか?remove()setremove

4

7 に答える 7

17

ThreadLocalとがMapあるため、それを使用していたスレッドの値を削除しないと、メモリ リークが発生しますcurrentThreadvalue

ThreadLocalクラスはThreadLocal.Values localValues で定義され たThreadクラスから値を設定するため、常にremoveを呼び出す必要があります。これにより、Thread および関連オブジェクトの参照も保持されます。

のソースコードからThreadLocal

値は null に設定され、基になるエントリは引き続き存在します。

于 2012-09-14T12:49:05.290 に答える
15

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 レベルはかなり移動しましたが、最小サイズはまだ小さかったです。

于 2012-09-14T12:47:44.760 に答える
4

set: このスレッドローカル変数の現在のスレッドのコピーを指定された値に設定します。

つまり、その記憶場所にあったものはすべて、通過したものによって上書きされますset

于 2012-09-14T12:48:41.870 に答える
3

あなたがしようとしている変数がスレッドの次の実行にremove常にある場合set、それを削除することについて心配する必要はありません。setその値を上書きします。

ただし、その変数を特定の状況でのみ設定している場合 (たとえば、特定の種類の要求のみを処理する場合)、それを削除すると便利な場合があります。プール。

于 2012-09-14T12:50:23.600 に答える
1

簡単に説明します。なんらかの理由で ThreadLocal を拡張する場合は、 を使用しますremove()。バニラで ThreadLocal を使用しますset(null)。基本的ThreadLocal.remove()に、拡張されたThreadLocal で使用しないと、メモリ リークが発生する可能性があります (ClassLoader の可能性が最も高い)。

理由の詳細が必要な場合は、コメントを投稿してください。

于 2012-09-14T13:16:39.393 に答える