在java中如何创建一个内存泄露

今天访问java 并发编程网,看到一个翻译征集令,并发编程网的作者从stackoverflow 网站上选取了一些经典问答,遂决定翻译几篇

征集令地址:http://ifeve.com/stackoverflow-assembly/

翻译系列文章:

1.Java 核心类库中的一些设计模式

2. hashMap 与hashTable之间的区别

3.在java中如何创建一个内存泄露


译文:

在java中如何创建一个内存泄露

问题: 我之前参加了一个面试, 被问到在java中如何创建一个内存泄露。不用说我当时不知道说啥,如何创建一个,我到现在也没有头绪。

可以给我示范一个例子么?


回答1:

有一个方式可以创建一个纯Java的内存泄露(运行代码中对象不可达,但仍然驻留在内存里)

1. 应用创建了一个长时间运行的线程(或者使用线程池,这会使内存泄露更快)
2.线程从类加载器加载一个类

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中没有类回收的选项,并阻止无用的类被垃圾回收

查阅  IBM jdk settings



原文:

原文地址:http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java








展开阅读全文

没有更多推荐了,返回首页