2024年4月30日发(作者:)
一、OOM含义:
OOM,全称“OutOfMemory”,意思是“内存用完了”。它来源于
emoryError。
二、为什么会出现emoryError:即OOM:
官方介绍为当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没
有空间可回收时,就会抛出emoryError:···(注意:这是个很严重的
问题,因为这个问题已经严重到不足以被应用处理)。
具体原因大致为两方面:
1、自身原因:比如虚拟机本身可使用的内存太少。
2、外在原因:如应用使用的太多,且用完没释放,浪费了内存。此时就会造成内存
泄露或者内存溢出。
内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段
内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。
内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。
三、OOM的error类型
首先说一下JAVA虚拟机运行时会管理的内存区域吧:
1.程序计数器:当前线程执行的字节码的行号指示器,线程私有
虚拟机栈:Java方法执行的内存模型,每个Java方法的执行对应着一个栈帧
的进栈和出栈的操作。
3.本地方法栈:类似“JAVA虚拟机栈”,但是为native方法的运行提供内存环境。
堆:对象内存分配的地方,内存垃圾回收的主要区域,所有线程共享。可分
为新生代,老生代。
5.方法区:用于存储已经被JVM加载的类信息、常量、静态变量、即时编译器编译
后的代码等数据。Hotspot中的“永久代”。
6.运行时常量池:方法区的一部分,存储常量信息,如各种字面量、符号引用等。
7.直接内存:并不是JVM运行时数据区的一部分,可直接访问的内存,比如NIO会
用到这部分。
所以除了程序计数器不会抛出OOM外,其他各个内存区域都可能会抛出OOM。
常见OOM情况:
emoryError:Javaheapspace------>java堆内存溢出,此种情
况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存
监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-ms,-m等修改。
emoryError:PermGenspace------>java永久代溢出,即方法
区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因
为上述情况会产生大量的Class信息存储于方法区。当出现此种情况时可以通过更改方法
区的大小来解决,使用类似-:PermSize=64m-:MaPermSize=256m的形式修改。注意,
过多的常量尤其是字符串也会导致方法区溢出。
verflowError------>不会抛OOMerror,但也是比较常见的Java
内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,
栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-ss来设置栈的大小。
四、OOM分析
HeapDump(堆转储文件)它是一个Java进程在某个时间点上的内存快照。
HeapDump是有着多种类型的。不过总体上heapdump在触发快照的时候都保存了
java对象和类的信息。通常在写heapdump文件前会触发一次FullGC,所以
heapdump文件中保存的是FullGC后留下的对象信息。
通过设置如下的JVM参数,可以在发生OutOfMemoryError后获取到一份HPROF
二进制HeapDump文件:
-:+HeapDumpOnOutOfMemoryError
生成的文件会直接写入到工作目录。
注意:该方法需要JDK5以上版本。
转存堆内存信息后,需要对文件进行分析,从而找到OOM的原因。可以使用以下方
式:
mat:eclipsememoryanalyzer,基于eclipseRCP的内存分析工具。具体使用参考:
/mat/,推荐使用。
jhat:JDK自带的javaheapanalyzetool,可以将堆中的对象以html的形式显示出
来,包括对象的数量,大小等等,并支持对象查询语言OQL,分析相关的应用后,可以
通过localhost:7000来访问分析结果。不推荐使用。
发布评论