Java教程

ThreadLocal内存泄露的原因及避免 -- java面试

本文主要是介绍ThreadLocal内存泄露的原因及避免 -- java面试,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

内存泄漏

不会再被使用的对象或者变量占用的内存不能被回收,就是内存泄露。

强引用与弱引用

强引用:使用最普遍的引用(New),一个对象具有强引用将不会被GC回收。当内存空间不足时,jvm宁愿抛出OutOfMemoryError错误使程序终止,也不回收这种对象。

弱引用:使用java.lang.ref.WeakReference表示。jvm在进行垃圾回收时,无论内存是否充足,都会回收这种对象。

ThreadLocal的内存泄露分析

ThreadLocal的实现原理:每一个Thread维护一个ThreadLocalMap,key为使用弱引用的ThreadLocal实例,value为线程变量的副本。

ThreadLocal在没有外部强引用时,发生GC时会被回收,如果创建ThreadLocal的线程一直持续运行,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露。

那为什么使用弱引用而不是强引用

假如hreadLocalMap的key为强引用,回收ThreadLocal时,因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,因而value也不会被回收,导致Entry内存泄漏。

让key(threadLocal对象)为弱引用,自动被垃圾回收,key就变为null了,下次,我们就可以通过Entry不为null,而key为null来判断该Entry对象该被清理掉了。

Entry的key被设计为弱引用就是为了让程序自动地对访问不到的数据进行回收,所以,在访问不到的数据被回收之前,内存泄漏确实是存在的,但是我们不用担心,就算我们不调用remove,ThreadLocalMap在内部的set,get和扩容时都会清理掉泄漏的Entry,内存泄漏完全没必要过于担心

因此,ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key就会导致内存泄漏,而不是因为弱引用。

ThreadLocal正确的使用方法

  • 每次使用完ThreadLocal都调用它的remove()方法清除数据

  • 将ThreadLocal变量定义成private static,设计为static的,被class对象给强引用,线程存活期间就不会被回收。这样就一直存在ThreadLocal的强引用,也就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉 。


参考链接:
《提升能力,涨薪可待》-ThreadLocal的内存泄露的原因分析以及如何避免 - 掘金
Java中ThreadLocal的实际用途是啥? - 知乎
谈谈ThreadLocal为什么被设计为弱引用 - 知乎

这篇关于ThreadLocal内存泄露的原因及避免 -- java面试的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!