核心问题:ThreadLocalMap中Entry继承了WeekReference,为什么要这样做?
- Hotspot虚拟机下一个类User继承另一个类Person后,在对User类实例化时堆中一共创建了几个对象(不考虑编译优化)?答:一个,调用顺序父类clinit(()->子类clinit()->父类init()->子类init()
- 如果创建了两个对象,那么父类对象的指针/引用保存在子类对象的哪块区域的?答:chatgpt说的保存在子类的对象头的,感觉不对,对象头里面不是只有markword、classpoint、数组长度么,chasspointer、数组长度么!
- 一个类继承了WeekReference,那么这个类在实例化时,他保存了一个指向其父类WeekReference对象的指针/引用吗?答:继承的类的实例化在只会生成一个对象的情况下,是不存在这种可能的
- WeekReference有一个成员变量referent,是对一个对象的弱引用还是对一个对象的强引用的弱引用吗?答:应该是指向了这个对象强引用的弱引用,两个引用指向同一个内存地址,所以==也是为true的
- GC时这个被referent引用的对象一旦只被这个referent引用,那么就会被GC回收吗?答:当垃圾回收器开始工作时,无论当前内存是否足够,都会回收到只被弱引用关联的对象。也就是说如果这个弱引用关联的对象被其他对象强引用或者软引用引用着,就不会在本次垃圾收集时被回收
- 如果referent引用的ThreadLocal对象不被其他引用引用,就代表其维护的value值也不会再被访问了,那么这个继承了WeekReference类的Entry对象会被回收吗? 答:如果referent会回收,因为entry对象本身被threadLocalMap强引用着,所以不会被回收,只能通过用户代码显式的调用threadLocal.remove()方法才能删除对这个entry对象的引用。
ThreadLocal实现过程:每个线程Thread都有一个ThreadLocalMap的成员变量(Entry[]实现的,以下简称map),在调用一个ThreadLocal的get/set方法时,实际上会拿到当前这个Thread的map,然后对ThreadLocal进行hash取模运算后拿到一个map中的下标,通过这个下标来存取Entry,Entry继承了WeakReference类(简称Reference),这个Reference类有一个referent的成员变量,除此之外Entry有一个value的成员变量,referent作为一个弱引用指向ThreadLocal对象在堆中的内存地址(Java为什么要通过引用来访问对象,通过虚、弱、软、强在垃圾回收时进行不同的处理逻辑),当垃圾回收器工作时,并且ThreadLocal对象只被这个referent弱引用指向着时,那么这个对象就会被回收。因为Entry被map强引用着,所以不会被回收,Entry的value引用所指向的对象被Entry强引用着也不会被回收,所以存在内存泄漏。因此,线程使用完了ThreadLocal需要显式的调用其remove()方法清除对Entry、Value的强引用,这个remove()方法会不管有没有同时清除对Reference对象的软引用