有一个方式可以创建一个纯Java的内存泄露(运行代码中对象不可达,但仍然驻留在内存里)
1. 应用创建了一个长时间运行的线程(或者使用线程池,这会使内存泄露更快)
今天访问java 并发编程网,看到一个翻译征集令,并发编程网的作者从stackoverflow 网站上选取了一些经典问答,遂决定翻译几篇
征集令地址:http://ifeve.com/stackoverflow-assembly/
翻译系列文章:
问题: 我之前参加了一个面试, 被问到在java中如何创建一个内存泄露。不用说我当时不知道说啥,如何创建一个,我到现在也没有头绪。
可以给我示范一个例子么?
3. 这个类分配一个大内存块(例如new byte[1000000]) ,把它通过强引用指向一个静态成员变量,然后把它自己的引用存储到ThreadLocal 中。分配巨大的内存这一步是可选的(泄露类的实例是足够的,只不过这样做将会使泄露更快发生)
4.线程清除所有自定义类的引用 或者让类加载器重新载入
5.重复以上步骤
这样是可以的,因为ThreadLocal存储了这个对象的一个引用,这个对象引用类本身,类本身引用一个类加载器,类加载器引用了它加载的所有类。
内存泄露将变得越来越严重,因为在许多Java 虚拟机的实现中,类和类加载器被直接分配在permgen代,而且一直没有被回收。
这种模式的一个变种是,当你碰巧使用了任何形式的TreadLocal, 并且频繁的部署一个应用,应用容器(例如 tomcat)会像一个筛子一样不断泄露内存。
(因为应用容器使用了之前描述的那种线程,你每次重新部署应用,一个新的类加载器就会被使用)
更新:因为很多人在问,所以我这里提供了一些例子展示这种情况here's some example code that shows this behavior in action.
回答2:
静态字段持有对象引用
class MemorableClass {
static final ArrayList list = new ArrayList(100);
}
使用很长的字符串调用 String.intern()
String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you cant remove
str.intern();
打开的流未关闭 ( file , network 等等)
try {
BufferedReader br = new BufferedReader(new FileReader(inputFile));
...
...
} catch (Exception e) {
e.printStacktrace();
}
未关闭的连接
try {
Connection conn = ConnectionFactory.getConnection();
...
...
} catch (Exception e) {
e.printStacktrace();
}
JVM垃圾回收器不可达的区域
比如通过本地方法分配的内存
In web applications objects stored in application scope till application is restarted or removed explicitly
在Web 应用中,直到应用明确的被重启或被删除,对象一直存贮在应用中
getServletContext().setAttribute("SOME_MAP", map);
session.setAttribute("SOME_MAP", map);
Incorrect or inappropriate JVM options
不正确的或者不合适的JVM选项
比如在IBM JDK中没有类回收的选项,并阻止无用的类被垃圾回收