1、什么是内存泄漏?
内存的空间有一定的大小,当内存过载超过本身的空间范围(前提:一些内存无法进行回收),那么就叫做内存泄漏,在页面显示中体现为页面卡死或卡顿。
2、ThreadLocal基本原理
在多线程并发访问同一个共享变量的时候,如果不做同步控制的话,就可能会导致数据不一致的问题,这是就用synchronized来加锁进行解决,而ThreadLocal换了一种思路来解决多线程的情况。
(1)ThreadLocal本身不存储数据,ThreadLocal的作用主要是做数据隔离,填充的数据只属于当前线程,变量的数据对别的线程而言是相对隔离的,在多线程环境下,防止自己的变量被其它线程篡改。
(2)每个线程自己的链接是靠ThreadLocal保存的。
(3)ThreadLocal在保存的时候会把自己当做Key存在ThreadLocalMap中,正常情况应该是key和value都应该被外界强引用才对,但是现在key被设计成WeakReference弱引用了。
这就导致了一个问题,ThreadLocal在没有外部强引用时,发生GC时会被回收,如果创建ThreadLocal的线程一直持续运行,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露。
就比如线程池里面的线程,线程都是复用的,那么之前的线程实例处理完之后,出于复用的目的线程依然存活,所以,ThreadLocal设定的value值被持有,导致内存泄露。
解决方法:
方法一:在代码的最后使用remove就好了,我们只要记得在使用的最后用remove把值清空就好了。
ThreadLocal<String> localName = new ThreadLocal();
try {
localName.set("张三");
……
} finally {
localName.remove();
}
方法二:将ThreadLocal变量尽可能地定义成static final
这样的话就可以避免频繁的去创建ThreadLocal实例,这样就能保证,程序一定会存在ThreadLocal的强引用,也能够通过ThreadLocal的弱引用,去访问Entry的Value值从而清除。
知识点补充:
Java中的四种对象引用关系:
强引用:只要强引用关系还存在,对象就永远不会被回收
软引用:在内存溢出前对其进行回收
弱引用:不管内存是否够用,下次GC一定回收
虚引用:等同于没有引用,回收时会收到一个系统通知