JavaOOM原因以及解决⽅案
1)什么是OOM? OOM,全称“Out Of Memory”,翻译成中⽂就是“内存⽤完了”,来源于java.lang.OutOfMemoryError。看下关于的官⽅说明: Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector. 意思就是说,当JVM因为没有⾜够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error(注:⾮exception,因为这个问题已经严重到不⾜以被应⽤处理)。
2)为什么会OOM?
为什么会没有内存了呢?原因不外乎有两点:
1)分配的少了:⽐如虚拟机本⾝可使⽤的内存(⼀般通过启动时的VM参数指定)太少。
2)应⽤⽤的太多,并且⽤完没释放,浪费了。此时就会造成内存泄露或者内存溢出。
内存泄露:申请使⽤完的内存没有释放,导致虚拟机不能再次使⽤该内存,此时这段内存就泄露了,因为申请者不⽤了,⽽⼜不能被虚拟机分配给别⼈⽤。
内存溢出:申请的内存超出了JVM能提供的内存⼤⼩,此时称之为溢出。
在之前没有垃圾⾃动回收的⽇⼦⾥,⽐如C语⾔和C++语⾔,我们必须亲⾃负责内存的申请与释放操作,如果申请了内存,⽤完后⼜忘记了释放,⽐如C++中的new了但是没有delete,那么就可能造成内存泄露。偶尔的内存泄露可能不会造成问题,⽽⼤量的内存泄露可能会导致内存溢出。
⽽在Java语⾔中,由于存在了垃圾⾃动回收机制,所以,我们⼀般不⽤去主动释放不⽤的对象所占的内存,也就是理论上来说,是不会存在“内存泄露”的。但是,如果编码不当,⽐如,将某个对象的引⽤放到了全局的Map中,虽然⽅法结束了,但是由于垃圾回收器会根据对象的引⽤情况来回收内存,导致该对象不能被及时的回收。如果该种情况出现次数多了,就会导致内存溢出,⽐如系统中经常使⽤的缓存机制。Java中的内存泄露,不同于C++中的忘了delete,往往是逻辑上的原因泄露。
3)OOM的类型
JVM内存模型:
按照JVM规范,JAVA虚拟机在运⾏时会管理以下的内存区域:
程序计数器:当前线程执⾏的字节码的⾏号指⽰器,线程私有
JAVA虚拟机栈:Java⽅法执⾏的内存模型,每个Java⽅法的执⾏对应着⼀个栈帧的进栈和出栈的操作。
本地⽅法栈:类似“ JAVA虚拟机栈 ”,但是为native⽅法的运⾏提供内存环境。
JAVA堆:对象内存分配的地⽅,内存垃圾回收的主要区域,所有线程共享。可分为新⽣代,⽼⽣代。
⽅法区:⽤于存储已经被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Hotspot中的“永久代”。字符串常量池存的是实例还是引用?
运⾏时常量池:⽅法区的⼀部分,存储常量信息,如各种字⾯量、符号引⽤等。
直接内存:并不是JVM运⾏时数据区的⼀部分,可直接访问的内存,⽐如NIO会⽤到这部分。
按照JVM规范,除了程序计数器不会抛出OOM外,其他各个内存区域都可能会抛出OOM。
最常见的OOM情况有以下三种:
java.lang.OutOfMemoryError: Java heap space ------>java堆内存溢出,此种情况最常见,⼀般由于内存泄露或者堆的⼤⼩设置不当引起。对于内存泄露,需要通过内存监控软件查程序中的泄露代码,⽽堆⼤⼩可以通过虚拟机参数-Xms,-Xmx等修改。
java.lang.OutOfMemoryError: PermGen space ------>java永久代溢出,即⽅法区溢出了,⼀般出现于⼤
量Class或者jsp 页⾯,或者采⽤cglib等反射机制的情况,因为上述情况会产⽣⼤量的Class信息存储于⽅法区。此种情况可以通过更改⽅法区的⼤⼩来解决,使⽤类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致⽅法区溢出。
java.lang.StackOverflowError ------> 不会抛OOM error,但也是⽐较常见的Java内存溢出。JAVA虚拟机栈溢出,⼀般是由于程序中存在死循环或者深度递归调⽤造成的,栈⼤⼩设置太⼩也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的⼤⼩。
4)OOM分析--heapdump
要dump堆的内存镜像,可以采⽤如下两种⽅式:
设置JVM参数-XX:+HeapDumpOnOutOfMemoryError,设定当发⽣OOM时⾃动dump出堆信息。不过该⽅法需要JDK5
以上版本。
使⽤JDK⾃带的jmap命令。"jmap -dump:format=b,file=heap.bin <pid>" 其中pid可以通过jps获取。
dump堆内存信息后,需要对dump出的⽂件进⾏分析,从⽽到OOM的原因。常⽤的⼯具有:
mat: eclipse memory analyzer, 基于eclipse RCP的内存分析⼯具。详细信息参见:/mat/,推荐使⽤。
jhat:JDK⾃带的java heap analyze tool,可以将堆中的对象以html的形式显⽰出来,包括对象的数量,⼤⼩等等,并⽀持对象查询语⾔OQL,分析相关的应⽤后,可以通过localhost:7000来访问分析结果。不推荐使⽤,因为在实际的排查过程中,⼀般是先在⽣产环境 dump出⽂件来,然后拉到⾃⼰的开发机器上分析,所以,不如采⽤⾼级的分析⼯具⽐如前⾯的mat来的⾼效。
注意:因为JVM规范没有对dump出的⽂件的格式进⾏定义,所以不同的虚拟机产⽣的dump⽂件并不是⼀样的。在分析时,需要针对不同的虚拟机的输出采⽤不同的分析⼯具(当然,有的⼯具可以兼容多个虚拟机的格式)。IBM HeapAnalyzer也是分析heap的⼀个常⽤的⼯具。
到此这篇关于Java OOM原因以及解决⽅案的⽂章就介绍到这了,更多相关Java OOM内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论