我愛學習網-上傳
當前位置: 主頁 > 文庫 > Java >

ThreadLocal內存泄漏分析

時間:2020-08-24 12:32來源:我愛學習網 作者:apple 點擊:

 

目錄

 

  1. ThreadLocal.set方法源碼分析
  2. ThreadLocalMap.set方法源碼分析
  3. 內存泄漏分析

 

set方法源碼分析

 

  1. 獲取當前線程的threadLocals(ThreadLocalMap)
  2. 如果ThreadLocalMap為空則創建,否則設置value

 

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

 

為什么threadLocals是Map結構?

 

要解答這個問題需要看一下createMap部分。沒錯,key是當前ThreadLocal實例,一個線程是可以由多個ThreadLocal實例的,所以使用map結構

 

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

 

ThreadLocalMap.set方法源碼分析

 

根據key,value創建Entry,將entry放入key的hash值對應tab表對應下標處

 

Entry結構實現

 

可以看到entry的key是對ThreadLocal的弱引用。回憶下,弱引用會在下一次gc時被回收掉。引用API文檔中的解釋:https://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html

 

 

 

Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references are most often used to implement canonicalizing mappings.
弱引用對象,弱引用并不會阻止它們引用指向的對象變得可終結、終結,然后被回收。弱引用通常用于實現規范化映射。
Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references. At the same time it will declare all of the formerly weakly-reachable objects to be finalizable. At the same time or at some later time it will enqueue those newly-cleared weak references that are registered with reference queues.

 

假定垃圾回收器在某刻確定對象是弱可達的。此時,它將原子性的清除弱可達對象的所有弱引用,以及所以其他弱可達對象的所有弱引用,從這些通過強引用和軟引用鏈可訪問到的弱可達對象。同時它將聲明所有以前的弱可達對象都是為可終結的。同時或以后某個時候它將新清除的弱引用壓入使用引用隊列注冊的弱引用的引用隊列中。

 

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

 

 

內存泄漏分析

 

如果GC回收了Entry的key對ThreadLocal的弱引用。那么key為null,也就永遠不可能再訪問到50MB的value。此時便出現了泄漏。那么ThreadLocal既然使用了弱引用會不考慮該問題嗎?那么我們來繼續分析它的源碼

 

set部分

 

可以看到set值時,如果發現存在老的entry的key為null會觸發遍歷tab表清楚掉所有key為null的entry

 

for (Entry e = tab[i];
     e != null;
     e = tab[i = nextIndex(i, len)]) {
    ThreadLocal<?> k = e.get();

    if (k == key) {
        e.value = value;
        return;
    }

    if (k == null) {
        replaceStaleEntry(key, value, i);
        return;
    }
}

 

get部分

 

get部分也會清楚entry的key為null的數據,但是前提是get的key未獲取到時:getEntryAfterMiss

 

private Entry getEntry(ThreadLocal<?> key) {
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];
    if (e != null && e.get() == key)
        return e;
    else
        return getEntryAfterMiss(key, i, e);
}

 

總結

 

ThreadLocal內存泄漏須要滿足以下條件

 

  1. 線程沒有終結
  2. GC回收掉了弱引用
  3. 沒有再次調用ThreadLocal的set、get方法
  4. 沒有手工清除數據,即沒有調用remove方法
------分隔線----------------------------
    ?分享到??
看看啦
主站蜘蛛池模板: 国产免费av一区二区三区| 无码人妻一区二区三区免费手机| 精品一区二区三区电影| 国产精品丝袜一区二区三区| 亚洲A∨精品一区二区三区下载 | 久久久91精品国产一区二区| 成人免费一区二区三区在线观看| 中文字幕一区二区人妻性色 | 精品在线视频一区| 成人免费视频一区二区三区| 精品黑人一区二区三区| 日韩精品中文字幕无码一区| 国产内射在线激情一区| 国产日韩AV免费无码一区二区 | 韩国福利一区二区美女视频 | 久久精品人妻一区二区三区| 国产一区二区三区樱花动漫| 日韩成人一区ftp在线播放| 亚洲中文字幕乱码一区| 无码一区二区三区AV免费| 精品无码国产一区二区三区AV| 亚洲综合一区二区国产精品| 国产一区二区精品| 99久久精品国产一区二区成人| 国产成人久久精品一区二区三区| 另类一区二区三区| 日韩精品无码中文字幕一区二区 | 国产福利一区二区三区在线视频| 亚洲av成人一区二区三区| 国产99视频精品一区| 人妻互换精品一区二区| 色欲AV蜜桃一区二区三| 国产一区二区三区免费在线观看| 国产无人区一区二区三区| 无码人妻一区二区三区在线水卜樱 | 国产美女露脸口爆吞精一区二区| 一区二区三区免费视频网站| 伊人精品视频一区二区三区| 久久久久久人妻一区精品| 天堂va在线高清一区| 日本精品视频一区二区|