Java面试之Jvm内存泄漏

简介: 详细讲解Jvm内存泄漏

今天我们讲解一下Jvm内存泄漏

内存泄漏和内存溢出的关系

内存泄露:指程序中动态分配内存给一些临时对象,但是对象不会被GC所回收,它始终占用内存。即被分配的对象可达但已无用。
内存溢出:指程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。

从定义上可以看出内存泄露是内存溢出的一种诱因,但是不是唯一因素。

可以使用Runtime.getRuntime().freeMemory()进行内存泄漏查询

Runtime.getRuntime().freeMemory()表示当前还有多少空闲内存

package com.one.util;

public class Hello {
    public static void main(String[] args) {
        System.out.println("free内存:" + Runtime.getRuntime().freeMemory() / 1024
            / 1024);
        String[] aaa = new String[2000000];
        for (int i = 0; i < 2000000; i++) {
            aaa[i] = new String("aaa");
        }
        System.out.println("free内存:" + Runtime.getRuntime().freeMemory() / 1024 / 1024);
    }
}

此时结果如下所示

20190719100158797

内存泄漏的例子

如果长生命周期的对象持有短生命周期的引用,就很可能会出现内存泄露

比如下面的代码,这里的object实例,其实我们期望它只作用于method1()方法中,且其他地方不会再用到它,但是,当method1()方法执行完成后,object对象所分配的内存不会马上被认为是可以被释放的对象,只有在Simple类创建的对象被释放后才会被释放,严格的说,这就是一种内存泄露。

public class Simple {
 
    Object object;
 
    public void method1(){
        object = new Object();
        //...其他代码
    }
}

怎么解决上面的问题呢,加上下面的蓝色代码注释就好了

public class Simple {
 
    Object object;
 
    public void method1(){
        object = new Object();
        //...其他代码
        // 蓝色代码注释开始
        object = null;
        // 蓝色代码注释结束
    }
}

集合里面的内存泄漏

集合里面的数据都设置成null,但是集合内存还是存在的

比如下面的代码
因为你已经在下面的蓝色代码注释里面进行company=null了,所以下面的list集合里面的数据都是无用的了,但是此时list集合里面的所有元素都不会进行垃圾回收

package com.four;

import java.util.ArrayList;
import java.util.List;

public class Hello {
    public static void main(String[] args) {
        List<Company> list = new ArrayList<Company>();
        int i=0;
        for(int j=0;j<10;j++){
            Company company = new Company();
            company.setName("ali");
            list.add(company);
            // 蓝色代码注释开始
            company = null;
            // 蓝色代码注释结束
        }

        System.gc();
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("已经测试了"+(++i)+"秒");
        }
    }

}


class Company {
    private String name;

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("回收Comapny");
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

20190719095000536
怎么解决上面的问题呢,就是把上面的list集合变量也变成null,比如加上下面的红色代码注释

package com.one.util;

import java.util.ArrayList;
import java.util.List;

public class Hello {
    public static void main(String[] args) {
        List<Company> list = new ArrayList<Company>();
        int i = 0;
        for (int j = 0; j < 10; j++) {
            Company company = new Company();
            company.setName("ali");
            list.add(company);
            // 蓝色代码注释开始
            company = null;
            // 蓝色代码注释结束
        }
        // 红色代码注释开始
        list = null;
       // 红色代码注释结束
        System.gc();
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("已经测试了" + (++i) + "秒");
        }
    }

}

class Company {
    private String name;

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("回收Comapny");
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

此时结果如下所示,可以看出来集合里面的Company变量都回收了

2019071909522653

还有就是使用remove()方法进行移除元素的时候,也可能会造成内存泄漏

什么意思呢,
就比如ArrayList里面的pop(),如果是下面的写法就会造成内存泄漏,因为下面的elementData[--size]这个元素移除之后,并没有进行设置成null

public E pop(){
    if(size == 0)
        return null;
    else
        return (E) elementData[size];
}

所以上面的代码应该变成下面这样,此时注意下面的蓝色代码注释里面的size值比下面的红色代码注释里面的size小1

public E pop(){
    if(size == 0)
        return null;
    else{
        // 红色代码注释开始
        E e = (E) elementData[--size];
        // 红色代码注释结束
        // 蓝色代码注释开始
        elementData[size] = null;
        // 蓝色代码注释结束
        return e;
    }
}

连接没有关闭会泄漏

比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,这些链接在使用的时候,除非显式的调用了其close()方法(或类似方法)将其连接关闭,否则是不会自动被GC回收的。其实原因依然是长生命周期对象持有短生命周期对象的引用。所以我们经常在网上看到在连接调用结束的时候要进行调用close()进行关闭,这样可以回收不用的内存对象,增加可用内存。

能看到这里的同学,就帮忙点个赞吧,Thanks(・ω・)ノ

原文链接

目录
相关文章
|
8天前
|
缓存 easyexcel Java
Java EasyExcel 导出报内存溢出如何解决
大家好,我是V哥。使用EasyExcel进行大数据量导出时容易导致内存溢出,特别是在导出百万级别的数据时。以下是V哥整理的解决该问题的一些常见方法,包括分批写入、设置合适的JVM内存、减少数据对象的复杂性、关闭自动列宽设置、使用Stream导出以及选择合适的数据导出工具。此外,还介绍了使用Apache POI的SXSSFWorkbook实现百万级别数据量的导出案例,帮助大家更好地应对大数据导出的挑战。欢迎一起讨论!
|
15天前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
3天前
|
存储 运维 Java
💻Java零基础:深入了解Java内存机制
【10月更文挑战第18天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
15 1
|
6天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
20 5
|
5天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
14 1
|
6天前
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
12天前
|
监控 Java easyexcel
面试官:POI大量数据读取内存溢出?如何解决?
【10月更文挑战第14天】 在处理大量数据时,使用Apache POI库读取Excel文件可能会导致内存溢出的问题。这是因为POI在读取Excel文件时,会将整个文档加载到内存中,如果文件过大,就会消耗大量内存。以下是一些解决这一问题的策略:
38 1
|
14天前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
21 3
|
13天前
|
存储 监控 算法
Java中的内存管理与垃圾回收机制解析
本文深入探讨了Java编程语言中的内存管理方式,特别是垃圾回收机制。我们将了解Java的自动内存管理是如何工作的,它如何帮助开发者避免常见的内存泄漏问题。通过分析不同垃圾回收算法(如标记-清除、复制和标记-整理)以及JVM如何选择合适的垃圾回收策略,本文旨在帮助Java开发者更好地理解和优化应用程序的性能。
|
4天前
|
算法 Java
JAVA 二叉树面试题
JAVA 二叉树面试题
10 0