ThreadLocal引起内存泄露?

问题描述

[ 由于SimpleDateForamt是非线程安全的,所以想用ThreadLocal封装一下,但是同事说这样写会造成内存泄露,要请教一下各位,下面这样写会造成内存泄露么,烦请大伙给指点指点,不胜感激。(环境springmvc + spring +ibatis,使用了线程池)public class DateUtil {private static ThreadLocal<DateFormat> sdf = new ThreadLocal<DateFormat>() {protected DateFormat initialValue() {return new SimpleDateFormat("yyyy-MM-dd");};};public static DateFormat getDateFormat(ThreadLocal<DateFormat> tl) {return tl.get();}public static String format(Date date) {if (date == null) {return "";}return getDateFormat(sdf).format(date);}public static Date parse(String st) throws ParseException {return getDateFormat(sdf).parse(st);}}

解决方案

要整明白你的问题,你需要先搞懂几个技术点,1: ThreadLocal的底层原理http://www.iteye.com/topic/103804 这有一个文章你可以参考,其实最好的办法就是自己看源码。这里一个关键性的问题就是你要清楚ThreadLocal内部并没有Map,而是线程对象内部有一个Map,而ThreadLocal是把自己当做Key,去访问线程对象当中的Map2: Web环境的建成池,也就是说Web服务器会有一个线程池,每次请求到达服务器端的时候就会从里面拿一个线程(假设线程A)去完成这次请求,那么当执行到你上面代码的时候就会往当前线程的MAP里放一个FORMAT对象,那么假设又有很多次请求由不同的线程完成(B,C,D) 那么他们的MAP当中同样都会放入一个FORMAT对象,然后再请求结束以后这些线程又回到线程池当中等待下次请求。然后紧接着又有请求过来了,假设这时候又是线程A去处理,那么当在执行上面的代码的时候{return tl.get()},不会在去新创建对象了,而是把线程A当中之前设置进去的对象拿出来直接用,所以不会存在内存泄露的问题。但是有一个问题就是会导致WEB服务器线程池内的所有线程的MAP当中都有一个format对象。因为你在线程结束的时候并没有清除掉。
解决方案二:
JDK 文档:引用每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
解决方案三:
会有内存泄露,只有创建没有销毁。
解决方案四:
很抱歉,我的回答是错误的,如果误导了楼主,在此道歉,我犯了个想当然的错误,或者是记忆有误,把以前错误的想法写出来了。通过分析源码,可以知道,每个Thread对象都有如下对象,分别是给ThreadLocal和InheritableThreadLocal这两个对象用的。 /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; /* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;然后在以上两个ThreadLocal相关的类中,他们在取数据的时候,是以当前的ThreadLocal做为key去这map中取value的,并且在线程退出的时候,JVM会调用Thread类的一个私有方法,让此线程有机会去清除一些内部使用的资源,其中就包括了以上两个map,源码如下: /** * This method is called by the system to give a Thread * a chance to clean up before it actually exits. */ private void exit() { if (group != null) { group.threadTerminated(this); group = null; } /* Aggressively null out all reference fields: see bug 4006245 */ target = null; /* Speed the release of some of these resources */ threadLocals = null; inheritableThreadLocals = null; inheritedAccessControlContext = null; blocker = null; uncaughtExceptionHandler = null; }并且在ThreadLocal的实现中,为了不强引用ThreadLocal对象,采用了一个Entry对象以弱引用的方式引用着ThreadLocal对象,并以强引用的方式引用着value。再次表示抱歉,误导了楼主以及其他看客。
解决方案五:
首先,这种做法没有额外开销,因为只有到get的时候,才会真正初始化DateFormat。也不会泄露,不会出现所谓“Thread对象也没有办法GC”的情况,因为是Thread对象本身维护的Map,而不是ThreadLocal。
解决方案六:
每个请求一个线程,每个线程有自己的ThreadLocalMap存new SimpleDateFormat()如果有100个请求是不就有好几百个对象(甚至更多)的开销?
解决方案七:
首先假设你这个是web项目,当一个请求来的时候,web服务器会用一个线程去服务这个请求,这个时候,你就会为此线程绑定一个SimpleDateFormat对象在ThreadLocal里面,所以随着请求的越来越多,有可能,只是有可能,你的ThreadLoad里面的SimpleDateFormat对象会越来越多,说有可能是因为WEB服务器会有一个线程池,但是线程池并不代表线程就永远不会结束,当一个线程结束了的时候,你没有从ThreadLocal中移除对应的SimpleDateFormat,并且你看了ThreadLocal的实现你就知道,里面维护着一个Map,key就是对应的线程,所以长久以后,就会造成Thread由于有强引用,所以它即使退出了,Thread对象也没有办法GC,他对应的value,也就是SimpleDateFormat也没有办法回收,长久下来肯定就会内存泄漏了。其实要解决也挺简单的,只需要保证remove方法会被调用就可以了,你可以在Filter里面保证调用一下remove就可以防止内存泄漏了。
解决方案八:
这篇文章分析的ThreadLocal内存泄露分析http://liuinsect.iteye.com/blog/1827012

时间: 2024-10-31 15:55:49

ThreadLocal引起内存泄露?的相关文章

ThreadLocal的内存泄露(转)

ThreadLocal的目的就是为每一个使用ThreadLocal的线程都提供一个值,让该值和使用它的线程绑定,当然每一个线程都可以独立地改变它绑定的值.如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极大地简化你的程序. 关于的ThreadLocal更多内容,请参考<ThreadLocal>. 在阅读了ThreadLocal的源码后,我发现如果我们使用不恰当,可能造成内存泄露.经我测试,内存泄露的确存在.虽然该内存泄露,理论上上已经不算严重. 测试代码如下 Threa

ThreadLocal可能引起的内存泄露(转)

  小结ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题.在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性.http://sunnylocus.iteye.com/blog/801949 ThreaLocal是通过数据隔离机制来解决线程同步问题的 如果涉及到多个线程需要共享同一数据 比如计数器 此时在面临线程同步问题时就只能采取sync

实例详解Java中ThreadLocal内存泄露_java

案例与分析 问题背景 在 Tomcat 中,下面的代码都在 webapp 内,会导致WebappClassLoader泄漏,无法被回收. public class MyCounter { private int count = 0; public void increment() { count++; } public int getCount() { return count; } } public class MyThreadLocal extends ThreadLocal<MyCount

ThreadLocal是否会引发内存泄露的分析 good

这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和在什么情况下会内存泄露?   带着这些疑问,自己模拟了一下ThreadLocal.ThreadLocalMap的结构,先展示下自己涉及的结构: 自己实现一个simple的ThreadLocalMap,里面用一个entry用来存放由自己模拟的ThreadLocal调用set方法set进去的值. 并且和

如何用Java编写一段代码引发内存泄露

Q:刚才我参加了面试,面试官问我如何写出会发生内存泄露的Java代码.这个问题我一点思路都没有,好囧. A1:通过以下步骤可以很容易产生内存泄露(程序代码不能访问到某些对象,但是它们仍然保存在内存中): 应用程序创建一个长时间运行的线程(或者使用线程池,会更快地发生内存泄露). 线程通过某个类加载器(可以自定义)加载一个类. 该类分配了大块内存(比如new byte[1000000]),在某个静态变量存储一个强引用,然后在ThreadLocal中存储它自身的引用.分配额外的内存new byte[

android的GC内存泄露问题_Android

1. android内存泄露概念 不少人认为JAVA程序,因为有垃圾回收机制,应该没有内存泄露.其实如果我们一个程序中,已经不再使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成了内存泄露.如果我们的java运行很久,而这种内存泄露不断的发生,最后就没内存可用了.当然java的,内存泄漏和C/C++是不一样的.如果java程序完全结束后,它所有的对象就都不可达了,系统就可以对他们进行垃圾回收,它的内存泄露仅仅限于它本身,而不会影响整个系统的

用java创建一个内存泄露的步骤?

问题: 我之前参加了一个面试, 被问到在java中如何创建一个内存泄露.不用说我当时不知道说啥,如何创建一个,我到现在也没有头绪.可以给我示范一个例子么? 回答: 有一个方式可以创建一个纯Java的内存泄露(运行代码中对象不可达,但仍然驻留在内存里) 1. 应用创建了一个长时间运行的线程(或者使用线程池,这会使内存泄露更快)2.线程从类加载器加载一个类3. 这个类分配一个大内存块(例如new byte[1000000]) ,把它通过强引用指向一个静态成员变量,然后把它自己的引用存储到Thread

android的GC内存泄露问题

1. android内存泄露概念 不少人认为JAVA程序,因为有垃圾回收机制,应该没有内存泄露.其实如果我们一个程序中,已经不再使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成了内存泄露.如果我们的java运行很久,而这种内存泄露不断的发生,最后就没内存可用了.当然java的,内存泄漏和C/C++是不一样的.如果java程序完全结束后,它所有的对象就都不可达了,系统就可以对他们进行垃圾回收,它的内存泄露仅仅限于它本身,而不会影响整个系统的

关于Android聊天界面中用使用adapter导致内存泄露的问题,目前不知道如何改善,大神帮忙看看

问题描述 关于Android聊天界面中用使用adapter导致内存泄露的问题,目前不知道如何改善,大神帮忙看看 之前一段时间使用一段时间老是导致内存升高,而且内存也不回收,一步一步的排除了很多地方, 到最后发现问题是出在adapter中,但是也不知道怎么改了. 大神帮看看哪些地方会导致内存泄露! public void setmList(List mList) { if (isgroup) { isDiaplayNickName = SharePreferenceUtil.get_Boolean