发布于2022-01-06 08:14 阅读(682) 评论(0) 点赞(11) 收藏(2)
//ThreadLocal.ThreadLocalMap 类
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table;
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
Entry继承自弱引用,以保证只要发生GC就会回收掉引用对象。
这里经常有一个疑惑,回收的是Entry对象还是ThreadLocal对象。从理论上来说,Entry对象本身是强引用,使用弱引用的目的就是为了把WeakReference它所持有的泛型类型对象及时回收,所以回收的是ThreadLocal对象;
(Entry为什么使用弱引用?)
查看弱引用源码:
public class WeakReference<T> extends Reference<T> {
public WeakReference(T referent) {
super(referent);
}
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
//直接看Reference类
public abstract class Reference<T> {
//引用对象
volatile T referent;
//通过构造函数给引用对象赋值
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = queue;
}
//通过native方法获取该引用对象
@FastNative
private final native T getReferent();
//通过native方法自动回收引用对象
@FastNative
native void clearReferent();
//提供给java调用的主动回收对象的方法
public void clear() {
clearReferent();
}
}
(demo测试:)
ThreadLocal<String> a = new ThreadLocal<>();
ThreadLocal<String> b = new ThreadLocal<>();
Entry[] f = new Entry[2];
private void testgc(){
f[0] = new Entry(a, "aaa");
f[1] = new Entry(b, "bbb");
for (Entry entry : f) {
System.out.println(entry);
}
a = null;
Log.d(TAG, "start gc");
System.gc();
Log.d(TAG, "after gc");
for (Entry entry : f) {
Log.d(TAG, "print entry:" + entry);
}
new Handler(getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
Log.d(TAG, "gc时机不确定,1秒后保证gc发生之后再打印:");
for (Entry entry : f) {
Log.d(TAG, "entry:" + entry);
}
}
}, 1000);
}
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
public Entry(ThreadLocal<?> threadLocal, Object value) {
super(threadLocal);
this.value = value;
}
@Override
public String toString() {
return "Entry{" +
"value=" + value + "\n" +
"threadlocal=" + this.get() +
'}';
}
}
//log
MainActivity: start gc
MainActivity: after gc
MainActivity: print entry:Entry{value=aaa threadlocal=java.lang.ThreadLocal@d997cd4}
MainActivity: print entry:Entry{value=bbb threadlocal=java.lang.ThreadLocal@e5aee7d}
MainActivity: gc时机不确定,1秒后保证gc发生之后再打印:
MainActivity: entry:Entry{value=aaa threadlocal=null}
MainActivity: entry:Entry{value=bbb threadlocal=java.lang.ThreadLocal@e5aee7d}
//结果显示:gc之后,f[0]对象仍存在,而threadlocal为null,
//说明只有内部的threadlocal被回收了
进一步说明弱引用回收的就是泛型类型对象;
**引用:**存储在方法区的变量池、运行时数据区的虚拟机栈、或堆对象中的引用句柄,引用是运行时符号,指向的是对象在堆内存中的地址;
**对象:**分配在堆内存中的实例数据;
内存泄漏是如何发生的?:通过可达性分析之后,没有GCRoots指向的对象会被回收,那么当一个对象在业务中不再使用需要释放却还有GCRoots引用指向的时候就发生了内存泄漏。
(通过源码查看泄漏位置:)
/**
* Remove the entry for key.
*/
private void remove(ThreadLocal<?> key) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) { //这里e.get()获取ThreadLocal为null
e.clear();//清空弱引用
expungeStaleEntry(i); //清空Enty和其中的value
return;
}
}
}
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
// expunge entry at staleSlot
tab[staleSlot].value = null;
tab[staleSlot] = null;
size--;
//......
}
原文链接:https://blog.csdn.net/u013168615/article/details/122329872
作者:天天在家
链接:http://www.javaheidong.com/blog/article/372919/dcfa84079157dbea6fd7/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!