jvm内存泄漏

文章出自于:https://www.itqiankun.com/article/1564247928

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

内存泄露:指程序中动态分配内存给一些临时对象,但是对象不会被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);
    }
}

此时结果如下所示
在这里插入图片描述

内存泄漏的例子

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

比如下面的代码,这里的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;
    }
}

在这里插入图片描述
怎么解决上面的问题呢,就是把上面的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变量都回收了
在这里插入图片描述

还有就是使用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♪(・ω・)ノ

JVM内存泄露是指在Java虚拟机中,程序中动态分配的内存对象无法被垃圾回收机制回收,导致内存占用不断增加,最终导致内存耗尽的情况。内存泄露是内存溢出的一种诱因,但不是唯一因素。内存泄露通常发生在对象不再被程序使用,但由于某些原因(如被GC Root所引用)无法被回收的情况。实际上,一些疏忽或错误的编码习惯可能导致对象的生命周期变得很长甚至与JVM的生命周期一样,这也可以被称为宽泛意义上的"内存泄露"。在Java中,常见的内存泄露情况包括静态集合类中的对象未被正确释放等。要检测内存泄露,可以使用Runtime.getRuntime().freeMemory()方法进行查询。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [jvm内存泄漏](https://blog.csdn.net/weixin_43689480/article/details/96474346)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [JVM之内存泄露](https://blog.csdn.net/qq_50876039/article/details/122320924)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [jvm内存泄漏介绍](https://blog.csdn.net/magic_kid_2010/article/details/124173542)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值