蒲城县住房和城乡建设局网站,东莞seo建站优化哪里好,怎样推广自己的app,网站建设干货图书引子#xff1a; 内存泄漏#xff1a;是指本应该被GC回收的无用对象没有被回收#xff0c;导致内存空间的浪费#xff0c;当内存泄露严重时会导致内存溢出。Java内存泄露的根本原因是#xff1a;长生命周期的对象持有短生命周期对象的引用#xff0c;尽管短生命周期对象已… 引子 内存泄漏是指本应该被GC回收的无用对象没有被回收导致内存空间的浪费当内存泄露严重时会导致内存溢出。Java内存泄露的根本原因是长生命周期的对象持有短生命周期对象的引用尽管短生命周期对象已经不再需要但是因为长生命周期对象持有它的引用而导致不能被GC回收。 内存溢出就是我们常说的OOMOutOfMemoryError异常简单理解就是内存不够了通常发生在程序申请的内存超出了JVM中可用内存的大小就会抛出OOM异常。在JVM内存区域中除了程序计数器外其他的内存区域都有可能抛出OOM异常。 ThreadLocal很好地解决了线程之间需要数据隔离的问题同时也引入了另一个问题在应用程序中通常会使用线程池来管理线程那么线程的生命周期与应用程序的生命周期基本保持一致如果线程的数量很多随着程序的运行时间的推移ThreadLocal类型的变量会越来越多将会占用非常大的内存空间从而产生内存泄漏如果这些对象一直不被释放的话可能会导致内存溢出。 大家先看一下内存图 从图中可以看出ThreadLocal对象存在于堆中有栈中的强引用指向它也有ThreadLocalMap中的entry的弱引用键指向他。 “弱引⽤只要垃圾回收机制⼀运⾏不管JVM的内存空间是否充⾜都会回收该对象占⽤的内存。” 而随着程序的运行栈中ThreadLocal的强引用会消亡只剩下弱引用连接着ThreadLocal独享由于ThreadLocalMap.Entity中的key是弱引用所以堆中的ThreadLocal对象会被回收只要发生GC弱引用对象就会被回收但是ThreadLocalMap⽣命周期和Thread是⼀样的它这时候如果不被回收就会出现这种情况ThreadLocalMap的key没了value还在这就会造成了内存泄漏问题由弱引用引起的内存泄漏。
而对于线程来说线程的生命周期与应用程序的生命周期基本保持一致所以一直会存在Current Thread Refefence - Thread - ThreaLocalMap - Entry - value - Object的强引用这样value所强引用的Object对象迟迟得不到回收就会导致内存泄漏。 如何解决弱引用导致的内存泄露问题
ThreadLocalMap的设计中已经考虑到这种情况所以ThreadLocal的get()、set()、remove()的时候都会清除线程ThreadLocalMap里所有key为null的value。
一旦将value设置为null之后就斩断了引用与真实内存之间的强引用就能够真正的释放空间防止内存泄漏。
但是这只是一种被动的方式如果这些方法都没有被调用怎么办那你就每次使用完ThreadLocal变量之后执行remove方法。
总结ThreadLocalMap中的弱引用以及调用ThreadLocal各种方法后的清理只是增加了一层防护手段还是有可能会导致内存泄露真正想防止内存泄漏需要编码的规范使用完ThreadLocal后及时调用remove()方法释放内存空间。 那为什么还要维持一个弱引用呢
设置ThreadLocal对象的弱引用这样做的目的是确保ThreadLocal对象在没有其他强引用时可以被垃圾回收。
key设计成弱引⽤同样是为了防⽌内存泄漏这是另一个原因引起的内存泄漏。假如key被设计成强引⽤如果ThreadLocal Reference被销毁此时它指向ThreadLoca的强引⽤就没有了但是此时key还强引⽤指向ThreadLoca就会导致ThreadLocal不能被回收这时候就发⽣了内存泄漏的问题。
两个内存泄漏问题是不一样的 这里是ThreadLocal变量无法被回收导致内存泄漏 而弱引用导致的则是Value指向的object无法被回收导致内存泄漏 总结
首先如果让key使用强引用指向ThreadLocal则ThreadLocal对象无法被回收导致内存泄漏为了解决这个问题让key使用弱引用指向Threadlocal而这也会导致了Value无法被回收造成内存泄漏如何解决呢我们在使用完ThreadLocal对象后及时使用remove方法释放内存空间即可。