导语
  了解过java虚拟机的读者都知道,在JVM的内存可以分为堆内存和非堆内存,在之前的博客中分享了关于JVM常见参数的配置。这次分享的内容主要是对堆和非堆内存参数的配置

  在Java程序运行的过程中,如果堆空间内存不足就会出现内存溢出的现象OOM。一旦是发生了内存溢出就会导致整个应用程序的退出,在一定情况下会影响业务的正常使用。为了解决这类的问题,Java虚拟机提供了一个参数 -XX:+HeapDumpOnOutOfMemoryError 通过这个参数可以在内存溢出的时候导出这个堆中所有的信息,与之配合使用的参数是指定放置的路径 -XX:HeapDumpPath

文章目录

  • 生成Dump文件
  • 分析Dump文件
    • 第一步 进入命令行输入如下命令
    • 第二步 点击文件装入
    • 第三步 选择对应的dump文件
    • 第四步 查看信息
  • 简单分析上面例子
  • 总结

生成Dump文件

public class DumpDemo{public static void main(String[] args){Vector v = new Vector();for (int i = 0;i<25;i++ ) {v.add(new byte[1*1024*1024]);}}
}
java -Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./a.dump DumpDemo

  很显然根据之前分享的内容进行判断,在20MB的堆空间中存放25MB的内容就会引起内存溢出的异常。
运行结果

bogon:dumpdemo nihui$ java -Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./a.dump DumpDemo
java.lang.OutOfMemoryError: Java heap space
Dumping heap to ./a.dump ...
Heap dump file created [15551766 bytes in 0.013 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat DumpDemo.main(DumpDemo.java:6)
bogon:dumpdemo nihui$

  可以看到,发生了内存溢出的异常,并且在当前目录下面创建一个内存溢出异常的dump文件

分析Dump文件

第一步 进入命令行输入如下命令

jvisualvm

第二步 点击文件装入

第三步 选择对应的dump文件


  对于这里会到出现内存溢出异常的地方,在主线程中出现内存溢出异常。

第四步 查看信息


注意: 图中所有的蓝色字体都可以进行点击

简单分析上面例子

  首先来介绍一下虚拟机启动参数

java -Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./a.dump DumpDemo

 启动参数中设置初始化堆内存大小为5MB,最大堆内存为20MB。在程序中执行了如下的代码,这段代码在上面图中显示首先创建了一个Vector的对象,然后循环往这个对象中添加1MB的内容

Vector v = new Vector();
for (int i = 0;i<25;i++ ) {v.add(new byte[1*1024*1024]);
}

这里需要注意下图中的内容,首先来看看在第0个问题有1048576个项,而1024*1024正好是这个值。也就是说,其中的一项就表示在Vector中的一个元素。一共有20个其中创建到第14个的时候就内存溢出了。当然这其中还有其他的内容。

查找最大对象的前20个,发现前两个大小就已经是30MB左右了,总的大小设置为20这个时候就会出现堆内存也无法分配导致内存溢出。

最后加上GC参数之后在来启动项目

java -Xmx20m -Xms5m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./b.dump DumpDemo

运行结果

bogon:dumpdemo nihui$ java -Xmx20m -Xms5m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./b.dump DumpDemo
**两次年轻代GC 也就是Minor GC**
[GC (Allocation Failure) [PSYoungGen: 483K->496K(1536K)] 13796K->13832K(15360K), 0.0005768 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 496K->496K(1536K)] 13832K->13856K(15360K), 0.0005231 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
**第一次Full GC**
[Full GC (Allocation Failure) [PSYoungGen: 496K->0K(1536K)] [ParOldGen: 13360K->13592K(13824K)] 13856K->13592K(15360K), [Metaspace: 2612K->2612K(1056768K)], 0.0024076 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]**第二次年轻代GC Minor GC**
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 13592K->13592K(15360K), 0.0003190 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] **第二次Full GC**
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 13592K->13580K(13824K)] 13592K->13580K(15360K), [Metaspace: 2612K->2612K(1056768K)], 0.0021040 secs] [Times: user=0.02 sys=0.01, real=0.00 secs] **发生内存溢出异常**
java.lang.OutOfMemoryError: Java heap space
Dumping heap to ./b.dump ...
Heap dump file created [14463001 bytes in 0.010 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat DumpDemo.main(DumpDemo.java:6)
**打印出堆栈信息**
HeapPSYoungGen      total 1536K, used 31K [0x00000007bf980000, 0x00000007bfc80000, 0x00000007c0000000)eden space 1024K, 3% used [0x00000007bf980000,0x00000007bf987c68,0x00000007bfa80000)from space 512K, 0% used [0x00000007bfa80000,0x00000007bfa80000,0x00000007bfb00000)to   space 512K, 0% used [0x00000007bfc00000,0x00000007bfc00000,0x00000007bfc80000)ParOldGen       total 13824K, used 13580K [0x00000007bec00000, 0x00000007bf980000, 0x00000007bf980000)object space 13824K, 98% used [0x00000007bec00000,0x00000007bf943218,0x00000007bf980000)Metaspace       used 2644K, capacity 4486K, committed 4864K, reserved 1056768Kclass space    used 289K, capacity 386K, committed 512K, reserved 1048576K
bogon:dumpdemo nihui$

简单分析

  • 1、首先两个参数 -Xmx20m -Xms5m 根据上篇博客可以知道,设置新生代和老年代总体大小为20MB,其中初始化的堆内存是5MB,也就是说当程序开始执行的过程中,初始堆内存是5MB。
  • 2、开始运行当第4次添加对象的时候发现5MB的初始化内被占满了就进行内存的扩展,可能从5MB扩展到了10MB,发生一次MinorGC,也就是上面第一次出现PSYoungGen年轻代GC。
  • 3、第二步扩展内存完成之后,再次进行内存对象的分配,到第9次添加对象的时候发现原来的10MB的空间不够用了。这次触发了第二次的年轻代GC。再次进行扩展这次将内存扩展为15MB左右。(这里有一点比较难理解的地方就是5MB的初始大小,这里的初始大小表示堆内存中年轻代和老年代一共只有5MB,如果进行内存扩展的话是对着两个部分一起进行了扩展。)继续操作,会发现调用了一次Full GC,这次GC其实没有对内存中的13MB左右的数据产生任何的回收效果。
  • 4、继续执行,发现在内存溢出之前,执行了一次年轻代的GC操作,这次将所有的内存扩展为20MB,也就是最大内存了。这个时候,继续分配对象就会导致FullGC,但是发现FullGC并没有影响到整个内存中的数据的大小因为在第二次FullGC的时候[ParOldGen: 13592K->13580K(13824K)] 13592K->13580K(15360K),发现这里的GC其实并没有发生变化。发现最后打印出来Heap信息中ParOldGen total 13824K, used 13580K 老年代的使用率达到了98%。也就是说没有办法继续进行对象分配操作,如果下次再次经过一次年轻代GC操作之后,就会导致内存溢出。
  • 5、到这一步如果继续创建对象则内存中没有对应的年轻代空间进行分配,发生Minor GC,这个时候由整个的20MB的空间都已经分配完了就没有办法继续扩展空间了,这个时候程序还继续向堆内存要空间,就会导致整个的内存溢出操作。

  这里说明一点个人的总结,只要能发生MinorGC,就不会造成堆内存的溢出。发生内存溢出的一个条件就是此时堆中数据经过Full GC 之后并没有多大的变化,也就是没有进行回收,这个时候继续分配空间的话就要发生MinorGC,如果不能发生MinorGC就会导致堆内存溢出。(此观点仅个人通过分析得出,如有不对请大家指正)

总结

  从整个的GC过程来看,可以结合上篇博客中JVM常见参数配置对于常见参数的配置并且提供了一张内存关系图读者可以简单的分析一下,上面观点也请大家在评论区指正。

JVM优化系列-详解JVM堆内存分析相关推荐

  1. JVM优化系列-详解JDK1.8 Metaspace 参数配置

    导语   在JVM中除了有堆内存参数配置以外,还有一些其他内存例如方法区.线程栈直接内存等等.他们与堆内存来说是相对比较独立的内存空间.与堆内存相比较这些内存与应用程序本身的关系不大,但是如果将其放到 ...

  2. JVM优化系列-详解常用的虚拟机调优参数

    导语   需要对虚拟机进行诊断,首先需要了解如何进行虚拟机的配合和跟踪,这里就来说说有那些虚拟机配置参数,通过它们来对虚拟机进行跟踪和配置. 文章目录 虚拟机跟踪调试参数 如何读懂虚拟机日志 GC基本 ...

  3. JVM由浅入深系列——详解垃圾收集器与内存分配策略

    文章目录 一.内存分配策略 1.引用计数算法 2.可达性分析算法 3.标记清除算法 4.标记复制算法 5.标记整理算法 二.收集器 1.Serial收集器 2.ParNew收集器 3.Parallel ...

  4. java内存优化详解_jvm堆内存优化详解

    在日常的运维工作中用到tomcat,都需要对tomcat中的jvm虚拟机进行优化,只有知道需要优化参数的具体用处,才能深刻体会优化jvm的意义所在. 在平常的工作中我们谈对jvm的优化,主要是针对ja ...

  5. JVM 启动参数详解

    JVM 启动参数详解 JVM 作为一个通用的虚拟机,我们可以通过启动Java命令时指定不同JVM参数,让 JVM调整自己的运行状态和行为,内存管理和垃圾回收的GC算法等等. 直接通过命令行启动 Jav ...

  6. 详解JVM内存管理与垃圾回收机制5 - Java中的4种引用类型

    在Java语言中,除了基础数据类型的变量以外,其他的都是引用类型,指向各种不同的对象.在前文我们也已经知道,Java中的引用可以是认为对指针的封装,这个指针中存储的值代表的是另外一块内存的起始地址(对 ...

  7. 详解JVM内存管理与垃圾回收机制2 - 何为垃圾

    随着编程语言的发展,GC的功能不断增强,性能也不断提高,作为语言背后的无名英雄,GC离我们的工作似乎越来越远.作为Java程序员,对这一点也许会有更深的体会,我们不需要了解太多与GC相关的知识,就能很 ...

  8. Java开发常见面试题详解(JVM)_2

    Java开发常见面试题详解(JVM)_2 JVM 问题 详解 JVM垃圾回收的时候如何确定垃圾?是否知道什么是GC Roots link 你说你做过JVM调优和参数配置,请问如何盘点查看JVM系统默认 ...

  9. [java] 虚拟机(JVM)底层结构详解[转]

    [java] 虚拟机(JVM)底层结构详解[转] 本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 在以前的博客里面,我们介绍了在java领 ...

最新文章

  1. MEF程序设计指南七:使用目录(Catalog)动态装载xap与目录筛选(Filtered Catalog)...
  2. python--open用法
  3. 【转】【centos】启动网卡报错(Failed to start LSB: Bring up/down networking )解决办法总结...
  4. 使用通用mapper实现条件查询_【微服务】152:Stream流和通用mapper批量查询的使用...
  5. php反序列化总结与学习
  6. 苹果修复已遭在野利用的 iOS 和 macOS 0day
  7. HDU - 3506 Monkey Party
  8. 数字电子技术基础(第六版)阎石 版 课后答案 课后题答案与解析 课后习题答案
  9. 英尺、英寸、磅和厘米的换算
  10. NBA2K18手游显示无法连接服务器,nba2k18手游交易被拒绝 | 手游网游页游攻略大全...
  11. 考研350什么水平计算机,考研350分的难度相当于高考考什么水平?很多人都不知道...
  12. 2018拼多多校招【大整数相乘】Python解法
  13. teradata数据库--常用的数据字典表
  14. Oval验证框架学习
  15. Could not compile initialization script ‘C:\Users\***\AppData\Local\Temp\wrapper_init1.gradle‘.
  16. C++读取音频文件mp3、flac的曲名、歌手、专辑等ID3v2标签(使用libzplay)
  17. android800版本怎么隐藏软件,教你如何关闭MIUI9(10)的系统自带应用广告
  18. 使用DEAP基于K-means的情感计算
  19. 关于bootstrap-inputfile初始化加载图片,修改图片重新上传文件的坑
  20. C#实现串口监听(以中盛来电显示盒为例)

热门文章

  1. C盘文件内容及清理思路
  2. 【端午送福】13000 人正在学习的数据分析实战课,抽奖送送送!
  3. OSChina 周日乱弹 —— 七哥的北漂日记
  4. 12月13日云栖精选夜读 | 干货 :5个提醒,让你远离“数据呆”
  5. 修改Tomcat Connector运行模式,优化Tomcat运行性能
  6. jQuery formValidator表单验证插件4.1.1提供下载
  7. AgileEAS.NET平台开发Step By Step系列-药店系统-索引
  8. 让自己慢下来(2)-朋友们的回复
  9. 第一个Sprint冲刺成果
  10. jquery 选择器之children与find