要解答这个问题需要看一下createMap部分。没错,key是当前ThreadLocal实例,一个线程是可以由多个ThreadLocal实例的,所以使用map结构 根据key,value创建Entry,将entry放入key的hash值对应tab表对应下标处 可以看到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. 假定垃圾回收器在某刻确定对象是弱可达的。此时,它将原子性的清除弱可达对象的所有弱引用,以及所以其他弱可达对象的所有弱引用,从这些通过强引用和软引用链可访问到的弱可达对象。同时它将声明所有以前的弱可达对象都是为可终结的。同时或以后某个时候它将新清除的弱引用压入使用引用队列注册的弱引用的引用队列中。 如果GC回收了Entry的key对ThreadLocal的弱引用。那么key为null,也就永远不可能再访问到50MB的value。此时便出现了泄漏。那么ThreadLocal既然使用了弱引用会不考虑该问题吗?那么我们来继续分析它的源码 可以看到set值时,如果发现存在老的entry的key为null会触发遍历tab表清楚掉所有key为null的entry get部分也会清楚entry的key为null的数据,但是前提是get的key未获取到时:getEntryAfterMiss ThreadLocal内存泄漏须要满足以下条件
目录
set方法源码分析
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结构?
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
ThreadLocalMap.set方法源码分析
Entry结构实现
弱引用对象,弱引用并不会阻止它们引用指向的对象变得可终结、终结,然后被回收。弱引用通常用于实现规范化映射。
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; } }
内存泄漏分析
set部分
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部分
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); }
总结
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算