引言

本文仅关注一些常见的虚拟机内存监视手段,以及JVM运行时数据区各个部分内存溢出的发生和对应的解决方案,总体来说属于概括性总结,涉及相对不是很深入,目的是让自己和其它初学者有一个框架性、概念性的了解,当遇到问题时有迹可循、不至于不知所措。

一、虚拟机内存监视手段

虚拟机常出现的问题包括:内存泄露、内存溢出、频繁GC导致性能下降等,导致这些问题的原因可以通过下面虚拟机内存监视手段来进行分析,具体实施时可能需要灵活选择,同时借助两种甚至更多的手段来共同分析。

比如GC日志可以分析出哪些GC较为频繁导致性能下降、是否发生内存泄露。jstat工具和GC日志类似,同样可以查看GC情况、分析是否发生内存泄露。判断发生内存泄露后,可以通过jmap工具和MAT等分析工具的结合查看虚拟机内存快照,分析发生内存泄露的原因。内存溢出快照可以分析出内存溢出发生的原因等。

GC日志记录

将JVM每次进行GC的情况记录下来,通过观察GC日志可以看出来GC的频度、以及每次GC都回收了哪些区域的内存,根据这些信息为依据来调整JVM相关设置,可以减少Minor GC的频率以及Full GC的次数,还可以判断是否有内存泄露发生。

下面是常见的GC日志输出参数:

u  -verbose.gc:显示GC的操作内容。打开它,可以显示最忙和最空闲收集行为发生的时间、收集前后的内存大小、收集需要的时间等。

u  -XX:+printGCdetails:详细了解GC中的变化。

u  -XX:+PrintGCTimeStamps:了解垃圾收集发生的时间,自JVM启动以后以秒计量。

u  -XX:+PrintHeapAtGC:了解堆的更详细的信息。

u  -Xloggc:[file]:将GC信息输出到单独的文件中

jstat:虚拟机统计信息监控工具

实时监视虚拟机运行时的类装载情况、各部分内存占用情况、GC情况、JIT编译情况等。

例:每隔250ms查询一次进程2211的垃圾收集情况,查询50次

步骤①:jps列出本机所有运行的jvm实例,获取jvm的pid

步骤②:jstat实时监控gc情况,jstat –gc 2211 250 50

其他参数包括:

-class监视类装载、卸载数量、总空间以及类装载所耗费时间

-gccapacity监视内容与-gc相同,输出主要关注堆各个区域用到的最大、最小空间

-gcutil监视内同与-gc相同,输出主要关注堆各个区域已使用空间所占总空间百分比

-gcnew监视新生代GC情况

-gcold监视旧生代GC情况

jmap:虚拟机内存映像工具

jmap工具可以让运行中的JVM生成Dump文件,当JVM内存出现问题时可以通过jmap生成快照,分析整个堆,主要经历两个步骤:

步骤1:jps列出本机所有运行的jvm实例,获取jvm的pid

步骤2:使用jmap命令将指定JVM快照导出为dump文件

jmap -dump:format=b,file=path/heap.bin PID   

获得JVM快照的dump文件之后,可以通过MAT工具进行分析。

MAT(MemoryAnalyzer Tool)工具是eclipse的一个插件,使用起来非常方便,尤其是在分析大内存的dump文件时,可以非常直观的看到各个对象在堆空间中所占用的内存大小、类实例数量、对象引用关系、利用OQL对象查询,以及可以很方便的找出对象GC Roots的相关信息,最吸引人的是能够快速为开发人员生成内存泄露报表,方便定位和分析问题。

除此之外,jmap还可以查询finalize执行队列、Java堆和持久代的详细信息,比如空间使用率,当前使用的是哪种收集器等。

内存溢出快照生成

通过设置JVM参数,可以让虚拟机发生OutOfMemoryError(OOM)内存溢出时自动生成dump文件,通过分析dump文件查看内存使用情况可以找到内存溢出发生的原因:

-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/path/to/heap/dump

获得JVM快照的dump文件之后,可以通过MAT工具进行分析。

二、运行时数据区内存溢出

JVM运行时数据区分为以下几个部分:

其中方法区和堆是所有工作线程共享的,而栈、程序计数器和本地方法栈是线程私有的。

注:图片转自网络

1.程序计数器

作用:指向当前线程下一条需要执行的字节码指令的地址

内存溢出:不会发生

2.虚拟机栈

作用:由栈帧组成、每个栈帧代表一次方法调用,其包含存储变量表、操作数栈和方法出口三个部分,方法执行完成后该栈帧将被弹出。

内存溢出:StackOverflowError和OutOfMemoryError。

溢出原因:

StackOverflowError:如果请求的栈的深度大于虚拟机所允许的深度,将会抛出这个异常,如果使用虚拟机默认参数,一般达到1000到2000这样的深度没有问题。

OutOfMemoryError:因为除掉堆内存和方法区容量,剩下的内存由虚拟机栈和本地方法栈瓜分,如果剩下的内存不足以满足更多的工作线程的运行、或者不足以拓展虚拟机栈的时候,就会抛出OutOfMemoryError异常。

解决方法:

针对StackOverflowError:

1.      首先栈溢出会输出异常信息,根据信息查看对应的方法调用是否出现无限调用、或者栈帧过大等代码逻辑上的问题,通过修改代码逻辑解决;

2.      如果确确实实需要更大的栈容量,可以检查并调大栈容量:-Xss16m。

针对OutOfMemoryError:

1.      首先检查是否创建过多的线程,减少线程数

2.      可以通过“减少最大堆容量”或“减少栈容量”来解决。

3.本地方法栈

作用:与虚拟机栈唯一的不同是虚拟机栈执行的是java方法,而本地方法栈执行的是本地的C/C++方法

内存溢出:StackOverflowError和OutOfMemoryError

溢出原因:同虚拟机栈

解决方法:同虚拟机栈

4.堆

作用:所有线程共享,存放对象实例

内存溢出:OutOfMemoryError:Javaheap space

溢出原因:堆中没有足够内存完成实例分配,并且无法继续拓展时

解决方法:

1.内存泄露检查:首先通过“内存溢出快照 + MAT等分析工具”,分析是否存在内存泄露现象,检查时可以怀疑的点比如集合、第三方库如数据库连接的使用、new关键字相关等。

2.如果没有内存泄露,那么就是内存溢出,所有对象却是都还需要存活,这个时候就只能调大堆内存了:-Xms和-Xmx。

5.方法区

作用:所有线程共享,存放已加载的class信息、常量、静态变量和即时编译后的代码

内存溢出:OutOfMemoryError:PermGen space

溢出原因:方法区没有足够内存完成内存分配存放运行时新加载的class信息

解决方法:

1. 内存泄露检查:检查是否加载过多class文件(jar文件),或者重复加载相同的class文件(jar文件)多次

2. 通过-XX:PermSize=64M -XX:MaxPermSize=128M改大方法区大小

6.运行时常量池

作用:方法区的一部分,存放常量

内存溢出:OutOfMemoryError:PermGen space

溢出原因:方法区没有足够的内存完成内存分配,存放运行时新创建的常量,比如String类的intern()方法,其作用是如果常量池已经包含一个相同的字符串,则返回其引用,否则将此String对象包含的字符串添加到常量池中。

解决方法:

1. 内存泄露检查:检查是否创建过多常量

2. 通过-XX:PermSize=64M -XX:MaxPermSize=128M改大方法区大小

7.直接内存

作用:不属于JVM运行时数据区,也不是虚拟机规范中定义的内存区域,JDK1.4引入的NIO中包含通道Channel和缓冲区Buffer,应用程序从通道获取数据是先经过OS的内核缓冲区,再拷贝至Buffer,因为比较耗时,所以Buffer提供了一种直接操作操作系统缓冲区的方式,即ByteBuffer.allocateDirector(size),这个方法返回DirectByteBuffer应用就是指向这个底层存储空间关联的缓冲区,即直接内存(native memory),或者叫堆外内存。

内存溢出:OutOfMemoryError

溢出原因:JVM所需内存 + 直接内存 > 机器物理内存(或操作系统级限制),无法动态拓展

判断方法:内存泄露检查:例如内存占用较高,机器性能骤降,但是通过GC信息或者jstat发现GC很少,通过jmap获得快照分析后也没发现什么异常,而程序中又直接或者间接地用到了NIO,那么和可能就是直接内存泄露了。

解决方法:分析NIO相关的程序逻辑解决。

JVM内存监视手段和内存溢出解决方案的更多相关文章

  1. JVM总结-内存监视手段及各区域内存溢出解决

    转载:https://blog.csdn.net/xuqu_volition/article/details/53786096 引言 本文仅关注一些常见的虚拟机内存监视手段,以及JVM运行时数据区各个 ...

  2. 应用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap space)

    http://www.educity.cn/wenda/351088.html 使用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap s ...

  3. 牛客网Java刷题知识点之内存溢出和内存泄漏的概念、区别、内存泄露产生原因、内存溢出产生原因、内存泄露解决方案、内存溢出解决方案

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

  4. PHP内存溢出解决方案

    一.内存溢出解决方案 在做数据统计分析时,经常会遇到大数组,可能会发生内存溢出,这里分享一下我的解决方案.还是用例子来说明这个问题,如下: 假定日志中存放的记录数为500000条,那么解决方案如下: ...

  5. Android内存溢出解决方案(OOM)

    众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视平台而定).因此在开发应用时需要特别关注自身的内存使用量,而一般最耗内存量的资源,一般是图片.音频文 ...

  6. JVM探秘:MAT分析内存溢出

    本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. MAT是分析Java堆内存的一个工具,全称是 The Eclipse Memory A ...

  7. 配置Tomcat的JVM的大小解决Tomcat内存溢出的问题

    操作步骤如下图所示(图中也有对应的文字说明已比较详细,不再用文字做过多的解释): 1: 2: 3: 4: 5: 下面是配置的参数的说明: -Xms256m                     JV ...

  8. Webpack编译提示内存溢出解决方案

    在项目开发中,随着业务需求的复杂项目随之增大,再加上同一个文件被引用次数过于频繁在开发编译或者上线打包时经常会出现如下错误: 这个报错的意思就是Node内存不足所导致的,我们都知道 Node 是基于V ...

  9. 深入理解JVM虚拟机11:Java内存异常原理与实践

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...

随机推荐

  1. java中数组是不是对象?

    [转自知乎]:http://www.zhihu.com/question/26297216 JAVA中的数组是对象吗? public class test { public static void m ...

  2. flashfxp 命令行

    以后更新软件时,尽量用bat命令行 http://www.flashfxp.com/forum/flashfxp/frequently-asked-questions-faq-/14748-comma ...

  3. UAC 注册表 WIN64 OS 运行时主题

    首先EXE程序是32位,DelphiIDE对Project默认是启用主题的,默认情况在WIN64 OS下运行时,无管理员权限. WIN64 OS,默认情况下UAC是启用的. 上述默认情况下,EXE 是 ...

  4. 读书笔记 C# Lookup<TKey,TElement>和ToLookup方法的浅析

    Lookup<TKey,TElement>类型对象和分组是一样的,就好比使用Linq的group关键字后所查询出来的结果,使用foreach的时候,都可以用IGrouping<TKe ...

  5. <NET CLR via c# 第4版>笔记 第18章 定制特性

    18.1 使用定制特性 FCL 中的几个常用定制特性. DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中. Serializable 特性应用于类型,告诉 ...

  6. 【数据库】MFC ODBC(四)

    7.滚动记录 CRecordset提供了几个成员函数用来在记录集中滚动.当用这些函数滚动到一个新记录时,框架会自动地把新记录的内容拷贝到域数据成员中. void MoveNext( ); //前进一个 ...

  7. 亚马逊Kindle正式进入中国

    6月7日下午消息,亚马逊Kindle今天下午4点正式发售.其中,Kindle电子阅读器和Kindle Fire平板电脑同步销售.Paperwhite售价最低849元,Kindle Fire HD售价最 ...

  8. L243 词汇题2009

    The applications of genetic engineering are abundant (plentiful) and choosing one appropriate for th ...

  9. oracle function用法(本文来自百度文库)

    函数调用限制 1.SQL语句中只能调用存储函数(服务器端),而不能调用客户端的函数 2.SQL只能调用带有输入参数,不能带有输出,输入输出函数 3.SQL不能使用PL/SQL的特有数据类型(boole ...

  10. Linux 内核链表实现和使用(一阴一阳,太极生两仪~)

    0. 概述 学习使用一下 linux 内核链表,在实际开发中我们可以高效的使用该链表帮我们做点事, 链表是Linux 内核中常用的最普通的内建数据结构,链表是一种存放和操作可变数据元 素(常称为节点) ...