定位JVM内存溢出问题思路总结
JVM的内存溢出问题,是个常见而有时候有非常难以定位的问题。定位内存溢出问题常见方法有很多,但是其实很多情况下可供你选择的有效手段非常有限。很多方法在一些实际场景下没有实用价值。这里总结下我的一些定位思路。
要定位JVM内存溢出问题,首先要对JVM的内存布局有一定的了解,对常见的JVM内存工具要比较熟悉。所谓工欲善其事,必先利其器。而熟悉JVM的内存管理机制是你定位JVM内存问题的基石。首先介绍下JVM的内存管理机制:
JAVA程序和C类程序一个重要的区别就是JAVA中的内存回收管理工作有JVM完成,而不需要为程序中的每个new/malloc去delete/free。那JVM这么智能怎么还有内存溢出问题呢,一个常见的原因是我们的JAVA程序中长时间的持有了不该持有的对象,或者申请了过多的对象使得JVM的内存不够用。
JVM管理的几个内存区域包括以下几个内存区域:
1、 方法区:用于存储JAVA类信息、常量、静态变量。这个区域也可以发生垃圾回收,比如当一些类不在被引用时JVM可以卸载这个类,不过这种回收动作很少发生。另外所有线程都共享方法区,因此线程对方法区的访问被设计为线程安全的。
2、 虚拟机栈:JAVA虚拟机栈是线程私有的,每当启动一个新线程时,JVM都会为它分配一个JAVA虚拟机栈。没当线程调用方法时,JVM都会为虚拟机栈压入一个栈帧,该栈帧用于存储参数、局部变量、中间运算结果、方法出口等。
3、 本地方法栈:和虚拟机栈类似,只是他是专为JAVA中的Native方法服务。当线程进入本地方法后,它已经脱离的JVM的限制,甚至可以直接使用本地处理器中的寄存器。实际上本地方法的调用机制非常依赖于JVM的具体实现。
4、 堆:由JVM启动时创建,由所有线程共享,用于存放对象的实例。一般情况下它是JVM中管理的内存中最大的一块。绝大部分JVM内存问题都发生在这一块。
5、 程序计数器:同虚拟机栈一样,它也是线程私有,启动线程是创建。程序计数器的中保存的内容总是下一条将被执行的指令的地址。
这几个内存区域,除了程序计数器区域外,其他几个区域都有可能发生内存溢出问题。常见的内存溢出有两种:
1、方法区溢出。出现该问题时,JVM会报如下类似错误:java.lang.OutOfMemoryError : PermGenSpace ,Perm区的最大内存大小可以通过-XX:MaxPermSize=指定。引起这类内存溢出原因一般有两个,一个是常量池太大,一个是需要加载的CLASS类太多。出现问题的时候排查下这两种可能性,问题可以很快找到。这类问题程序稳定后也很少出现。
2、堆内存溢出。在JVM可使用的最大堆内存可以在启动的时候通过-Xmx参数指定。堆内存溢出是最为常见的内存溢出问题,发生堆内存溢出时,JVM会报告如下错误:java.lang.OutOfMemoryError : java heap space。
这里列举下在定位堆内存溢出时,常见的方法和思路。堆内存溢出顾名思义就是,堆内存不够用了,如果程序设计的最大对内存已经耗尽,那说明程序设计存在问题,不该申请很多内存的逻辑申请了很多的内存,该释放的对象没有释放。最重要的问题是就要要找出到底是什么对象没有及时释放,导致占用了过多的内存。常见的方法:
a、 一个强大的定位工具是使用 jprofiler,通过jprofiler可以实时的监控到,当前的堆内存的总体使用情况及当前存活的对象、大小、分配树、对象引用链等等,功能非常全面。如下图所示:

通过该工具还可以实时的生成堆内存快照,然后通过不同时间点生成的内存快照做比较已确定内存增长点。但是实际使用中如果程序征程运行中占用的内存就比较高,比如800M左右,而在32位机器上,JVM可以使用的最高内存在1280M左右,如果应用程序设置的最大堆内存是1024M,那么实际即将发生堆内存溢出时,程序使用的内存是处一个比较高的位置。这时候通过jprofiler监控效果就很不理想,我在windows server 2003 32位服务器上做测试,想通过jprofiler监控一个TOMCAT应用程序,该应用程序常态中占用内存在800M左右,启用jprofiler监控后,jprofiler监控程序本身就会变得很不稳定,常常莫名挂死(通过jprofiler监控应用程序的时候实际上上jprofiler对应用程序又做了一层包装后启动的,因此jprofiler监控程序挂死,等于被监控的程序挂死)。很难抓取到有用的信息。
因此jprofiler在32位机器上只适用用小内存应用程序。
b、 使用JVM自带的jmap工具导出堆信息分析,这个工具可以通过如下命令到处自定的JVM进程的堆内存:jmap –dump:format=b,file=heap.bin <pid> 。
但这个工具也有一样的问题,在应用程序使用的内存处于高位时,使用jmap导出堆信息会出现空间不足,无法导出的问题。Java自带的很多工具都有类似的限制,所以实际上你的选择并不多。
c、 在启动JVM的时候加上以下两个参数:
-XX:HeapDumpPath=./dumpfile.hprof
-XX:+HeapDumpOnOutOfMemoryError
表示出现OOM错误后,将堆信息dump出来。不过这个参数也有个问题,在实际使用的时候发现在windows平台上,如果程序是以TOMCAT服务的方式运行,出现OOM错误后堆信息也dump不出来。
d、 通过visualVM程序监控JVM,JDK 1.6中自带的可视化监控工具,这个工具比较实用,功能也比较强大。可以监控线程信息,堆内存信息,还可以实时导出堆信息以及强制GC。监控本地JVM直接启动该工具后就可以监控,远程监控需要启动jstatd和jrxml。
启动jstatd方法:新建jstatd.all.policy文件,添加如下内容,tools.jar包的路径根据实际情况修改:
grant codebase "file:/home/ndmc/tomcat/jdk/jre/lib/tools.jar" {
permission java.security.AllPermission;
};
执行启动命令./jstatd -J-Djava.security.policy=jstatd.all.policy,默认端口为1099,后面可跟-p指定其他端口号
使用jrxml远程监控JVM的时候需要加上以下参数:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8849
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=hostip
监控效果如下:

在监控过程中可以手动的GC和DUMP堆内存,还可以设置Heap dump on OOME: enabled,使得在堆内存溢出的时候可以dump heap。不过根据实际使用,建议最高在堆内存即将溢出的时候就应该手动dump heap,因为等到OOM的时候常常程序已经挂死,heap已经导不出来了。
e、 导出dump信息后就可以通过jprofiler工具或者HeapAnalyzer做分析。这两个工具都很强大,网上有很多的使用指导。可以初步分析出到底是什么对象在占用内存,以及相应的引用链,到这一步在结合源代码在定位内存溢出问题就相对容易了。
总结:定位内存溢出问题需要一个冷静的头脑、敏锐的观察能力、缜密的分析问题能力。甚至常常需要根据一些现象做猜测然后验证,找出最后的元凶,有可能内存的溢出是有多个方面引起的:代码BUG、软件设计问题、网络的吞吐量以及网路连接问题、数据库问题等都可能是相关需要排查的因素,甚至有时候可能是操作系统或者JVM本身存在的BUG导致。而能够在JVM堆内存即将溢出的时候导出堆信息是问题定位的关键,只要能够导出堆信息,一系列的猜测、分析是否正确就有可靠的证据。
---------------------
原文:https://blog.csdn.net/xishanxinyue/article/details/15336551
定位JVM内存溢出问题思路总结的更多相关文章
- jvm内存溢出问题的定位方法
jvm内存溢出问题的定位方法 今天给大家带来JVM体验之内存溢出问题的定位方法. 废话不多说直接开始: 一.Java堆溢出 测试代码如下: import java.util.*; public cla ...
- JVM内存溢出分析java.lang.OutOfMemoryError: Java heap space
JVM内存溢出查询java.lang.OutOfMemoryError: Java heap space查出具体原因分为几个预备步骤 1.在运行java程序是必须设置jvm -XX:+HeapDump ...
- jvm内存溢出分析
概述 jvm中除了程序计数器,其他的区域都有可能会发生内存溢出 内存溢出是什么? 当程序需要申请内存的时候,由于没有足够的内存,此时就会抛出OutOfMemoryError,这就是内存溢出 内存溢出和 ...
- 老李案例分享:定位JAVA内存溢出
老李案例分享:定位JAVA内存溢出 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.在poptest的loadrunner的培 ...
- jvm 内存溢出问题排查方法
如果你做TCP通讯或者map集合操作,并发处理等功能时,很容易出现 Java 内存溢出的问题.本篇文章,带领大家深入jvm,分析并找出jvm内存溢出的代码. jvm中除了程序计数器,其他的区域都有可能 ...
- 5种JVM垃圾收集器特点和8种JVM内存溢出原因
先来看看5种JVM垃圾收集器特点 一.常见垃圾收集器 现在常见的垃圾收集器有如下几种: 新生代收集器: Serial ParNew Parallel Scavenge 老年代收集器: Serial O ...
- Tomcat中JVM内存溢出及合理配置及maxThreads如何配置(转)
来源:http://www.tot.name/html/20150530/20150530102930.htm Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚 ...
- Tomcat中JVM内存溢出及合理配置
Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识 ...
- JVM内存溢出及合理配置
Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识 ...
随机推荐
- manjaro配置
manjaro配置 Table of Contents manjaro配置 系统 一.初次使用 二.安装软件 输入法 emacs samba 三.配置修改 konsole shell颜色 系统 man ...
- 大数据面试题——如何从大量的url中找出相同的url
题目描述: 给定a.b两个文件,各存放50亿个url,每个url各占64B,内存限制是4GB,请找出a.b两个文件共同的url 分析: 由于每个url需要占64B,所以50亿个url占用空间大小为50 ...
- Linux3.10.0块IO子系统流程(5)-- 为SCSI命令准备聚散列表
SCSI数据缓冲区组织成聚散列表的形式.Linux内核中表示聚散列表的基本数据结构是scatterlist,虽然名字中有list,但它只对应一个内存缓冲区,聚散列表就是多个scatterlist的组合 ...
- mysql装完计算机管理里面没mysql服务怎么解决(转)
mysql装完计算机管理里面没mysql服务怎么解决 2017年07月04日 09:32:51 XC_Echizen 阅读数:7335 标签: mysql计算机mysql服务找不到mysql服务 更多 ...
- 史上最简单OpenGL+VS2017环境配置
这里采用 最简单的方法: (1)添加Nuget包管理器(方便我们为项目添加OpenGL的库) (2)新建一个项目 右键我们的项目名 ——> 管理NuGet程序包——>搜索nupengl,然 ...
- 互联网创业公司如何防御 DDoS 攻击?采用CDN服务
收集了发表于2015年 攻击者是控制一个足够大的分布式集群来发起攻击,各种杂七杂八的包,什么都会有.根本不在乎你开的什么服务,也没那耐心分析你有什么服务.比如哪怕你根本没开UDP的任何服务,但他就是发 ...
- oracle密码过期的修改
ALTER USER 用户名 IDENTIFIED BY 密码 ;
- JavaBasic_11
Object默认的实现是比较对象的地址 Object默认的实现是比较对象的地址局部内部类 局部位置内部类:局部是指方法体中 1.可以直接访问外部类的成员(这个特征是所有内部类所共有) 2.可以创建内部 ...
- python 的排名,已经python的简单介绍
我在今天看了一篇文章,是简书的全网程序猿写的,Java已经退出神坛,python稳居第一. python是由龟叔写的,它在英文的意思是蟒蛇. 根据编程语言流行指数排行榜2019年2月的榜单 据了解,目 ...
- Python全栈之路---数据类型—字符串
字符串:有序的字符的集合,用于存储和表示基本的文本信息,一对单.双.或三引号中间包含的内容称之为字符串 1.特性:有序,不可变(开辟新地址存储字符串,python解释器会定期清空不用了的已存储的) & ...