最近查找了很多关于OOM,甚至于Java内存管理以及JVM的相关资料,发现这方面的东西太多了,竟有一种眼花缭乱的感觉,要想了解全面的话,恐非一篇文章能说清的,因此按照自己的理解整理了一篇,剩下的还需要继续学习。

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的内存分析工具。详细信息参见:http://www.eclipse.org/mat/,推荐使用。
  • jhat:JDK自带的java heap analyze tool,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言OQL,分析相关的应用后,可以通过http://localhost:7000来访问分析结果。不推荐使用,因为在实际的排查过程中,一般是先在生产环境 dump出文件来,然后拉到自己的开发机器上分析,所以,不如采用高级的分析工具比如前面的mat来的高效。
这个链接:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html中提供了一个采用mat分析的例子 。
 
注意:因为JVM规范没有对dump出的文件的格式进行定义,所以不同的虚拟机产生的dump文件并不是一样的。在分析时,需要针对不同的虚拟机的输出采用不同的分析工具(当然,有的工具可以兼容多个虚拟机的格式)。IBM HeapAnalyzer也是分析heap的一个常用的工具。
 
5)小结
 
涉及到的虚拟机的技术或者工具,往往需要考虑到虚拟机规范以及不同的虚拟机实现。尤其是针对虚拟机调优时,往往需要针对虚拟机在某些方面的实现策略来考虑,比如,不同的虚拟机的垃圾回收算法是不一样的,而这直接影响了虚拟机某些参数的设置,以达到虚拟机的最佳性能。
而针对JVM运行时的分析与诊断,则需要掌握分析基本方法,针对具体情况,运用虚拟机的原理,具体分析。一句话,水很深啊。

什么是java OOM?如何分析及解决oom问题?的更多相关文章

  1. 记一次线上OOM问题分析与解决

    一.问题情况 最近用户反映系统响应越来越慢,而且不是偶发性的慢.根据后台日志,可以看到系统已经有oom现象. 根据jdk自带的jconsole工具,可以监视到系统处于堵塞时期.cup占满,活动线程数持 ...

  2. Java Web乱码分析及解决方式(一)——GET请求乱码

    引言:     在进行Web開始时.乱码是我们最常常遇到也是最主要的问题.有经验的程序员非常easy能解决,刚開始学习的人则easy被泥潭困住. 并且非常多时候.我们即使攻克了乱码问题也是不明就里.往 ...

  3. JAVA内存泄露分析及解决

    一,问题产生     项目采用Tomcat6.0为服务器,数据库为mysql5.1,数据库持久层为hibernate3.0,以springMVC3.0为框架,项目开发完成后,上线前夕进行稳定性拷机,测 ...

  4. Java Web乱码分析及解决方式(二)——POST请求乱码

    引言 GET请求的本质表现是将请求參数放在URL地址栏中.form表单的Method为GET的情况.參数会被浏览器默认编码,所以乱码处理方案是一样的. 对于POST请求乱码.解决起来要比GET简单.我 ...

  5. [转载] java中关于OOM的场景及解决方法

    1.OOM for Heap=>例如:java.lang.OutOfMemoryError: Java heapspace[分析] 此OOM是由于JVM中heap的最大值不满足需要,将设置hea ...

  6. Java中9种常见的CMS GC问题分析与解决

    1. 写在前面 | 本文主要针对 Hotspot VM 中"CMS + ParNew"组合的一些使用场景进行总结.重点通过部分源码对根因进行分析以及对排查方法进行总结,排查过程会省 ...

  7. Java中关于OOM的场景及解决方法(转)

    http://developer.51cto.com/art/201112/305696.htm 1.OOM for Heap=>例如:java.lang.OutOfMemoryError: J ...

  8. 左右c++与java中国的垃圾问题的分析与解决

    左右c++与java中国的垃圾问题的分析与解决 DionysosLai(906391500@qq.com)  2014/8/1 问题分析: 之所以会出现中文乱码问题,归根结底在于中文的编码与英文的编码 ...

  9. 文《左右c++与java中国的垃圾问题的分析与解决》一bug分析

    文<左右c++与java中国的垃圾问题的分析与解决>一bug分析 DionysosLai(906391500@qq.com) 2014/10/21 在前几篇一博客<关于c++与jav ...

随机推荐

  1. Shell变量相关

    li@ubuntu:~/test$ vi test.sh li@ubuntu:~/test$ cat test.sh #!/bin/bash #shell变量不加引号;加单引号;加双引号都行 url= ...

  2. java之定时任务

    package com.financial.server.util; import java.text.SimpleDateFormat; import java.util.Date; import ...

  3. mongoose与express

    一.mongoose的使用1.先创建一个项目目录,初始化:npm init -y2.创建一个server.js文件,在该目录下安装mongoose:cnpm install mongoose3.引入m ...

  4. 事务 c#

    事务->:事务是恢复和并发控制的基本单位 ->事务具有四个特性:原子性.隔离性.一致性.持久性.这四个特性通常称为ACID Begin transaction/tran   --开始事务 ...

  5. lnmp 安装redis-最全

    一. 安装redis 1.下载,解压,编译 $ wget http://download.redis.io/releases/redis-3.2.8.tar.gz $ tar -xzf redis-3 ...

  6. self: 限制并发量asyncio

    #coding:utf-8 import time,asyncio a=time.time() id=1 async def hello(id,semaphore): async with semap ...

  7. P4172 [WC2006]水管局长(LCT)

    P4172 [WC2006]水管局长 LCT维护最小生成树,边权化点权.类似 P2387 [NOI2014]魔法森林(LCT) 离线存储询问,倒序处理,删边改加边. #include<iostr ...

  8. oracle 12cR2 smart flash cache实测

    最近一直在处理新系统的性能优化问题,这两天特地测试了下oracle 11gR2开始引入的smart flash cache. 其介绍参考MOS文档,How To Size the Database S ...

  9. C#实现根据地图上的两点坐标,计算直线距离

    根据地图上的两点坐标,计算直线距离,在网上找到javascript的写法,用C#实现一下 /// <summary> /// 根据地图上的两点坐标,计算直线距离 /// </summ ...

  10. php mysqli 的使用方法

    原文链接:https://blog.csdn.net/solly793755670/article/details/52217456 Mysqli是php5之后才有的功能 需要修改php.ini的配置 ...