zoukankan      html  css  js  c++  java
  • 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);
        }
    }
    

    此时结果如下所示

    内存泄漏的例子

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

    比如下面的代码,这里的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♪(・ω・)ノ

    原文链接

  • 相关阅读:
    【SpringBoot系列】邮件发送
    【问题】InteliJ IDEA生成可执行jar运行提示没有主清单属性
    【设计模式】单例设计模式
    【C3P0】C3P0
    【JDBC】JDBC学习(一)
    react hook 防抖
    主线程 宏任务 微任务
    vue 2.0 渲染dom过程
    源码阅读笔记,杂乱
    vue 3.0 响应式原理
  • 原文地址:https://www.cnblogs.com/itqiankun/p/11302698.html
Copyright © 2011-2022 走看看