Java内存泄漏

时间:2020-07-01 09:17:15   收藏:0   阅读:66

Java内存泄漏

解释

内存泄漏: 存在一些被分配的对象,满足两个特点:

结果:消耗越来越多的内存资源,最终导致OutOfMemoryError

与C++的区别:

示例:

Vector v = new Vector(10);
for(int i = 0; i < 10;i++){
    Object o = new Object();
    v.add(o);
    o = null;
}

对象可以分为两种:有引用的对象无引用的对象
其中无引用的对象由GC进行回收。
有引用的对象不会被GC回收,即使这些对象不会再被使用。

技术图片


Java堆泄漏

注:通过-Xms<size>-Xmx<size>设置堆的最小值和最大值,使得容易的重现堆泄漏。

几种常见的泄漏情景:

存储对象引用的静态域

示例:

// JVM参数设定:-Xms10m -Xmx10m
// 会出现OutOfMemoryError
private Random random = new Random();
public static final ArrayList<Double> list = new ArrayList<>(1000000);
@Test
public void test() throws InterruptedException {
    for (int i = 0; i < 1000000; i++) { // 向static域加入对象
        list.add(random.nextDouble());
    }

    System.gc();
    Thread.sleep(10000); // 使得GC得以执行
}

使用非static域存放对象:

// 不会出现OutOfMemoryError
    @Test
    public void test() throws InterruptedException {
        addelement();
        System.gc();
        Thread.sleep(10000);
    }

    private void addelement(){
        ArrayList<Double> list = new ArrayList<>(1000000); // 使用非static域存储对象
        for (int i = 0; i < 1000000; i++) {
            list.add(random.nextDouble());
        }
    }

解决对策

对长字符串使用String.intern()

示例:

@Test
public void test() throws InterruptedException, FileNotFoundException {
    Thread.sleep(15000);
    String str = new Scanner(new File("scr/test.txt"),"UTF-8").useDelimiter("\\A").next();
    str.intern(); // 向字符串常量池中加入长字符串

    System.gc();
    Thread.sleep(16000);
}

解决对策

未关闭的流

// 流在使用后没有被关闭
@Test
public void test() throws IOException {
    String str = "";
    URLConnection conn = new URL("http://norvig.com/big.txt").openConnection();
    BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
    while (br.readLine() != null)
        str += br.readLine();
}

注:未关闭的流会导致两种类型的泄漏

解决对策

// 无需在finally中手动关闭
try (BufferedReader br = new BufferedReader(
  new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
    // ...
} catch (IOException e) {
    e.printStackTrace();
}

未关闭的连接

与未关闭的流类似。
一般是连接数据库或FTP后未关闭。

// 连接FTP后未关闭
@Test
public void test() throws IOException {
    URL url = new URL("ftp://speedtest.tele2.net");
    URLConnection urlc = url.openConnection();
    InputStream is = urlc.getInputStream();
    String str = " ";
}

解决对策

将没有hashCode()equal()的对象加入到Hashset

当一个对象没有重写hashCode()equals()方法时,在向HashSet集合类中添加重复的对象时,其不会忽略到重复的对象。

@Test
public void test(){
    Map<Object, Object> map = System.getProperties();
    while (true){
        map.put(new newObject("key"),"value");
    }
}

// 没有重写equals和hashCode的自定义类
class newObject{
    private String key;
    public newObject(String key){
        this.key = key;
    }
}

解决方法


查找泄漏源

参考:

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!