1.2 如何在Java中创建内存泄漏?| Java Debug 笔记

72 阅读2分钟

本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看<活动链接>

提问:如何在Java中创建内存泄漏?

我刚刚接受面试,并被面试官要求使用Java来实现一次内存泄漏。

不用说,我对如何开始实现它一无所知。

能否给出一个例子?

回答之前先解释下内存泄漏

内存泄露本意是申请的内存空间没有被正确释放,导致后续程序里这块内存被永远占用(不可达),而且指向这块内存空间的指针不再存在时,这块内存也就永远不可达了

热门回答:

可以通过满足以下条件来实现内存泄漏:

  1. 创建一个长时间运行的线程(使用线程池泄露的速度更快)。
  2. 线程通过ClassLoader加载某个类(也可以用自定义ClassLoader)。
  3. 这个类分配了大量内存(例如new byte[1000000]),赋给静态字段存储对它的强引用,然后在ThreadLocal中存储对自身的引用。还可以分配额外的内存,这样泄漏的速度更快(其实只要泄漏Class实例就足够了)。
  4. 这个线程会清除所有自定义类及加载它的ClassLoader的引用。
  5. 重复执行。

由于该方法ThreadLocal是在Oracle的JDK中实现的,因此会造成内存泄漏:

  • 每个Thread都有一个私有字段threadLocals,该字段实际上存储线程局部变量值。
  • ThreadLocalMap中的每个key都是对ThreadLocal实例的弱引用,因此在对该ThreadLocal对象进行垃圾回收时,会从map中删除这一键值对
  • 但每个值(线程要存的变量)本身又都是强引用,所以当一个值直接或间接指向ThreadLocal对象时,只要线程还存在,这个对象将永远不会被垃圾回收。