什么是内存溢出,内存泄漏?以及解决方案

一、Java是如何管理内存的?

  1. 在Java中,我们需要通过new关键字为每一个对象申请内存空间(基本数据类型除外),所有的对象都是在堆(Heap)中分配空间的。

  2. 在Java中,内存的分配是管理员决定的,但是内存的释放是由GC(Garbage Collection)完成的,这样收支两线的机制确实简化了程序员的工作量。

  3. 垃圾回收机制加重了JVM的工作,这也是Java程序执行速度比较慢的原因之一。GC为了能够正确、及时释放不再被引用的对象,GC必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。

  4. 在Java中,使用有向图的方式进行内存管理,精度高,但是效率较低,可以处理引用循环等问题。例如有三个对象互相引用,只要和根进程是不可到达的,就可以被GC回收。

  5. 另外一种常用的内存管理技术是使用计数器,例如COM模型采用计数器方式管理构件,它与有向图相比,精度低(很难处理循环引用的问题),但执行效率很高。

二、内存溢出和内存泄露的区别与联系

     内存溢出 (out of memory)  异常(OutOfMemoryError  StackOverflowError

           指程序要求的内存超出了系统所能分配的范围,出现out of memory;比如申请一个int类型,但给了它一个int才能存放的数,就会出现内存溢出,或者是创建一个大的对象,而堆内存放不下这个对象,这也是内存溢出。

 内存泄露 (memory leak)

           指程序在申请内存后,无法释放已申请的内存空间(指分配出去的内存无法被gc回收)。一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

 因此,我们从上面也可以推断出内存泄露可能会导致内存溢出。内存溢出会抛出异常,内存泄露不会抛出异常,大多数时候程序看起来是正常运行的。

三、内存溢出和内存泄露的案例

//内存溢出案例
public class demo {
    public static void main(String[] args) {
        List<Object> list=new ArrayList<>();
        while(true){//申请的内存过大
            int[] temp=new int[1000];
            list.add(temp);
        }
    }
}
//内存泄露案例
public class demo {
    public static void main(String[] args) {
        Vector<Object> v = new Vector<>(1000);
        for (int i = 1; i<1000; i++)
        {
            Object o = new Object();
            v.add(o);
            o = null;
        }
    }
}
  • JVM堆内存溢出:

    

    

  •  JVM栈内存溢出

     

    

四、内存溢出或泄露原因分析

  分析堆内存溢出的原因可能如下:

    1.使用了大量的递归或无限递归(递归中用到了大量的新建的对象)

    2.使用了大量循环或死循环(循环中用到了大量的新建的对象)

    3.类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;

    4.数组,List,Map中存放的是对象的引用而不是对象,因为这些引用会让对应的对象不能被释放,会大量存储在内存中。

  分析栈内存溢出的原因可能如下:   

    1.使用了大量的递归或无限递归

    2.使用了大量循环或死循环(如循环中不停调用方法)

    3.list,map,数组等长度过大等。

五、出现内存溢出或内存泄露的解决方案

         1.修改JVM启动参数(-Xms,-Xmx),直接增加虚拟机内存。

         2.检查错误日志。

         3.使用内存查看工具查看内存使用情况(如jconsole)

         4.对代码进行仔细分析,找出可能发生内存溢出的位置。

详细排查方案如下:

    1.检查在数据库中取的数据量是否超过内存

    2.检查是否有过大的集合或对象

    3.检查是死循环或递归是否会导致溢出

    4.检查是否有大量对象的创建是否会出现内存问题

    5.检查是否有大量的连接对象或监听器等未关闭..

六、在开发中应如何避免出现内存泄露

         1.尽量少使用枚举

         2.尽量使用静态内部类而不是内部类

         3.尽量使用轻量级的数据结构

         4.养成关闭连接和注销监听器的习惯

         5.谨慎使用static关键字

         6.谨慎使用单例模式

    ......

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liumce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值