Java虚拟机核心知识(三) 内存溢出和内存泄露

前言

上一章我们已经了解了Java虚拟机的内存模型、各个内存区域存储的内容以及OutOfMemory经常出现的区域。其实还有另外一个与OOM息息相关的概念: 内存泄露,这也是大家在面试经常碰到的问题,那么,它们之间究竟有什么联系与区别呢?本文为大家来详细解析一下。

二者的关系

内存泄漏(memory leak) : 指程序在申请内存后,无法释放已申请的内存空间,虽然一次内存泄漏似乎不会有大的影响,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

内存溢出(OutOfMemory): 指程序申请内存时,没有足够的内存供申请者使用,比如给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,即所谓的内存溢出。

而内存泄漏最终会导致内存溢出。

内存泄漏的分类

(1)常发性内存泄漏: 发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。

(2)偶发性内存泄漏: 发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。

(3)一次性内存泄漏: 发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。

(4)隐式内存泄漏: 程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

内存泄漏的检测

如果发现Java应用程序占用的内存出现了泄露的迹象,那么我们一般采用下面的步骤分析:

(1) 把Java应用程序使用的heap dump下来

(2) 使用Java heap分析工具,找出内存占用超出预期(一般是因为数量太多)的嫌疑对象

(3) 必要时,需要分析嫌疑对象和其他对象的引用关系。

(4) 查看程序的源代码,找出嫌疑对象数量过多的原因。

内存溢出的分类

Java堆溢出

对于Java堆溢出,一般通过内存映像分析工具(如Eclipse Memory Analyzer)对dump文件进行堆快照分析,确认内存中的对象是不是必要的:

(1) 如果对象不是必要的,那就属于内存泄漏,需要分析为什么对象没有被回收;

(2) 如果对象确实有必要继续存在,那就属于内存溢出,需要通过将堆的大小调高(-Xmx和-Xms)来避免内存溢出。

虚拟机栈和本地方法栈溢出

在Java虚拟机规范中,这个区域有两种异常情况:

(1) 如果线程运行时的栈帧的总大小超过虚拟机限制的大小,会抛出StackOverflow异常,这一点通常发生在递归运行时;

(2) 如果虚拟机栈设置为可以动态扩展,并且在扩展时无法申请到足够内存,则会抛出OutOfMemory异常。

对于栈的OutOfMemory异常,有下面两种情况:

在单个线程下,当栈的大小超过-Xss设置的大小限制时,抛出的都 是StackOverflowError;

在多线程的情况下,由于每创建一个线程,都需要划分一部分的内存,因此当机器内存已经被消耗干净时,再去创建线程,由于已经无法划分内存给新的线程,因此会导致OutOfMemory异常。

方法区溢出

方法区存储的是虚拟机加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据,在JDK1.7之前,HotSpot都是使用“永久代”来管理这些数据,也就是说,方法区的数据,其实也是属于堆内存的,会占用堆内存。

我们如果限制永久代的大小(-XX:MaxPermSize)比较小,那么很容易就会发生方法区溢出。

本机直接内存溢出

本机直接内存的容量可以通过-XX:MaxDirectMemorySize指定,如果不指定,默认与Java堆最大值一样。

本机直接内存溢出的一个明显特征是,dump文件很小。

参考资料

《深入理解Java虚拟机》 周志明

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值