首页 > 系统相关 >【JVM技术指南】「GC内存诊断-故障问题排查」一文教你如何打印及分析JVM的GC日志(实战分析上篇)

【JVM技术指南】「GC内存诊断-故障问题排查」一文教你如何打印及分析JVM的GC日志(实战分析上篇)

时间:2023-08-07 19:31:59浏览次数:41  
标签:XX secs GC 内存 JVM 日志

当我们在开发Java应用程序时,JVM的GC(垃圾回收)是一个非常重要的话题。GC的作用是回收不再使用的内存,以便程序可以继续运行。在JVM中,GC的日志记录了GC的详细信息,包括GC的类型、时间、内存使用情况等。在本文中,我们将介绍JVM GC日志的格式、含义和分析方法。


JVM GC日志格式

JVM GC日志的格式通常是一系列以时间戳为基础的事件,每个事件都包含了GC的详细信息。以下是一个典型的JVM GC日志的示例:

2021-01-01T00:00:00.000+0800: 1.000: [GC (Allocation Failure) 1.000: 1024K->512K(4096K), 0.0010000 secs]

其中,时间戳的格式为[ISO 8601],GC类型为“GC (Allocation Failure)”,GC发生的时间为1.000秒,GC前后内存使用情况分别为1024K和512K,总内存为4096K,GC耗时为0.001秒。


JVM GC日志含义

JVM GC日志包含了大量的信息,可以帮助我们了解JVM的内存使用情况和GC的性能。以下是一些常见的GC日志含义:

  • GC类型:GC的类型,如“GC (Allocation Failure)”表示由于内存分配失败而触发的GC。
  • 时间戳:GC发生的时间戳,通常是以秒为单位的浮点数。
  • 内存使用情况:GC前后内存使用情况,包括已使用内存、总内存等。
  • GC耗时:GC的耗时,通常是以秒或毫秒为单位的浮点数。

JVM GC日志分析方法

JVM GC日志的分析可以帮助我们了解JVM的内存使用情况和GC的性能,以便优化应用程序的性能。以下是一些常见的JVM GC日志分析方法:

  • 使用GCViewer等工具:GCViewer是一款免费的GC日志分析工具,可以帮助我们可视化地分析JVM GC日志。使用GCViewer可以轻松地查看GC的类型、时间、内存使用情况等。
  • 分析GC日志文件:我们可以使用文本编辑器等工具来分析GC日志文件。通过分析GC日志文件,我们可以了解GC的类型、时间、内存使用情况等,以便优化应用程序的性能。
  • 调整GC参数:通过调整JVM的GC参数,我们可以优化GC的性能,以便提高应用程序的性能。例如,我们可以通过调整-Xmx和-Xms参数来调整JVM的堆大小,以便优化GC的性能。

开启JVM-GC日志的启动参数

  1. 如果需要打印GC日志,那么首先得把JVM-GC日志进行输出到本地文件,一般我们会在JVM启动的时候添加参数:
  • -XX:+PrintGCDetails:打印GC日志细节
  • -XX:+PrintGCTimeStamps:打印GC日志时间
  • -Xloggc:gc_view.log:将GC日志输出到指定的磁盘文件上去,这里会把gc.log输出到项目根路径
  1. 当JVM在运行过程中如果发生GC,那么将会把GC日志输出到gc_view.log中。

GC查看案例

JVM参数中加入GC日志的打印选型,jvm参数如下所示:

-XX:NewSize=5242880 -XX:MaxNewSize=5242880 -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10485760 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+
PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log
JVM参数解析
配置JVM参数
  • -XX:NewSize=5242880 : 初始新生代大小
  • -XX:MaxNewSize=5242880:最大新生代大小
  • -XX:InitialHeapSize=10485760:初始堆大小
  • -XX:MaxHeapSize=10485760:最大堆大小
  • -XX:SurvivorRatio=8:Eden区就是Survivor区的8倍,所以Eden区占4M,两个Survivor都是占0.5M。
  • -XX:MaxTenuringThreshold=15:那么新生代对象只有达到15岁才会进入老年代。
  • -XX:PretenureSizeThreshold=10485760:指定了大对象阈值是10MB,那么只有大于10M的对象才能直接在老年代分配
  • -XX:+UseParNewGC:使用ParNew
  • -XX:+UseConcMarkSweepGC:CMS垃圾回收器

  • -XX:+PrintGCDetails:打印详细的gc日志
  • -XX:+PrintGCTimeStamps:这个参数可以打印出来每次GC发生的时间
  • -Xloggc:gc.log:这个参数可以设置将gc日志写入一个磁盘文件。
对象是如何分配在Eden区

我们针对于上述代码的内存进行分析,最开始我们定义和初始化了字节数组:new byte[1024 * 1024],并且对于同一个引用,我们分配了3个相同大小的字节数组,每个数组都是1MB。

public static void main(String[] args) {
    byte[] arrayInit = new byte[1024 * 1024];
    arrayInit = new byte[1024 * 1024];
    arrayInit = null;
    //触发Young GC
    byte[] arrayInit2 = new byte[2 * 1024 * 1024];
}
内存区域分析
  1. 定义array1这个局部变量依次引用这三个对象,最后还把 array1 这个局部变量指向了null,那么在JVM中是如何运行的呢?
初始化数组对象
byte[] arrayInit = new byte[1024 * 1024];。

在JVM的Eden区内存储一个1MB的对象,同时在main线程的栈中会压入一个main方法的栈帧,在main方法的栈帧内部,会有一个“arrayInit ”变量,这个变量是指向堆内存Eden区的那个1MB的数组。

【JVM技术指南】「GC内存诊断-故障问题排查」一文教你如何打印及分析JVM的GC日志(实战分析上篇)_数组

接着我们看第二行代码

arrayInit = new byte[1024 * 1024];

当执行了这行代码之后,便会在堆中的Eden区中再次分配一个数组,并且让之前的局部变量指向第二个数组,然后第一个数组就没人引用了,此时第一个数组就成了没人引用的“垃圾对象”了,如下图所示。

【JVM技术指南】「GC内存诊断-故障问题排查」一文教你如何打印及分析JVM的GC日志(实战分析上篇)_JVM_02

接着我们来看第三行代码:array1 = null; 这行代码一执行,就让arrayInit 这个变量什么都不指向了,此时会导致之前创建的2个数组全部变成垃圾对象,如下图。

【JVM技术指南】「GC内存诊断-故障问题排查」一文教你如何打印及分析JVM的GC日志(实战分析上篇)_sed_03

在项目的根路径下,就可以看到一个gc.log,点进去查看:

0.383: [GC (Allocation Failure) 0.384: [ParNew: 3543K->512K(4608K), 0.0024598 secs] 3543K->1828K(9728K), 0.0026607 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.386: [GC (Allocation Failure) 0.387: [ParNew: 2627K->0K(4608K), 0.0015255 secs] 3943K->1828K(9728K), 0.0015985 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
 par new generation   total 4608K, used 2089K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
  eden space 4096K,  51% used [0x00000000ff600000, 0x00000000ff80a558, 0x00000000ffa00000)
  from space 512K,   0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)
  to   space 512K,   0% used [0x00000000ffa80000, 0x00000000ffa80000, 0x00000000ffb00000)
 concurrent mark-sweep generation total 5120K, used 1828K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 3101K, capacity 4620K, committed 4864K, reserved 1056768K
  class space    used 327K, capacity 392K, committed 512K, reserved 1048576K

从上面内容中可以看到进行了两次GC。

0.383: [GC (Allocation Failure)
0.384: [ParNew: 3543K->512K(4608K), 0.0024598 secs] 3543K->1828K(9728K), 0.0026607 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

从上面的内容可以得出:

  • 在第0.383秒,发生Allocation Failure,就是给对象分配内存的时候内存空间不够了,
  • [ParNew: 3543K->512K(4608K),0.0024598 secs]
  • 新生代的总内存大小为4608KB(4M的Eden区加上了 0.5M的Survivor From区,一共是4.5M,即4608M);
  • Young GC之前,新生代占用内存大小为3543KB(三个1M的数组,加上471KB的“未知内容”);
  • Young GC之后,剩余了512KB(“未知内容”)。
  • 在第0.384秒的时候,使用ParNew垃圾回收器进行了Young GC。
  • 3543K->1828K(9728K)
  • 整个堆内存大小为9728KB(即4M的Eden区加上0.5M的Survivor区加上5M的老年代大小,9.5M,即9728KB)。
  • 在Young GC之前,堆内存共有3543KB内存被占用(三个1M的数组,加上471KB的“未知内容”);
  • 在Young GC之后,堆内存共有1828KB。

0.386: [GC (Allocation Failure) 
0.387: [ParNew: 2627K->0K(4608K), 0.0015255 secs] 3943K->1828K(9728K), 0.0015985 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

之后输出了Young GC之后的堆内存使用快照:

Heap
 par new generation   total 4608K, used 2089K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
  eden space 4096K,  51% used [0x00000000ff600000, 0x00000000ff80a558, 0x00000000ffa00000)
  from space 512K,   0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)
  to   space 512K,   0% used [0x00000000ffa80000, 0x00000000ffa80000, 0x00000000ffb00000)
 concurrent mark-sweep generation total 5120K, used 1828K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 3101K, capacity 4620K, committed 4864K, reserved 1056768K
  class space    used 327K, capacity 392K, committed 512K, reserved 1048576K

可以看到新生代占用了2098KB(一个2M的数组,还有一点“未知内容”);Eden区被占用了51%,Survivor From和Survivor To使用率为0%,CMS管理的老年代被使用了1828KB。


结论

JVM GC日志是一个非常重要的话题,可以帮助我们了解JVM的内存使用情况和GC的性能。通过分析JVM GC日志,我们可以优化应用程序的性能,提高应用程序的稳定性和可靠性。

标签:XX,secs,GC,内存,JVM,日志
From: https://blog.51cto.com/alex4dream/6996734

相关文章

  • 2023.8 模拟赛日志
    2023暑假集训ab班day1127round。预期:\(0+25+0=25\)实际:\(80+20+0=100\)题目:23ab-day1划(待写)不会做,搞了很久最后逐一假掉。竟然有分。题解是一些恶心的区间分类,比较简单,可惜了。好像有很多做法23ab-day1Heinrich树论科技,跳过。写了暴力换根。23ab-day1朝花夕拾......
  • 【Rabbitmq】报错:ERROR CachingConnectionFactory Channel shutdown: channel error
    目录01报错原因02解决方案2.1全局配置2.2注解方式原文链接:【Rabbitmq】报错:ERRORCachingConnectionFactoryChannelshutdown:channelerror异常信息Channelshutdown:channelerror;protocolmethod:#method<channel.close>(reply-code=406,reply-text=PRECONDITI......
  • linux GCC升级版本
    一、查看gcc版本首先查看当前gcc版本:gcc-v[mpshen@bigdata01~]$gcc-vUsingbuilt-inspecs.COLLECT_GCC=gccCOLLECT_LTO_WRAPPER=/usr/local/gcc/libexec/gcc/x86_64-unknown-linux-gnu/4.9.2/lto-wrapperTarget:x86_64-unknown-linux-gnuConfiguredwith:./configure......
  • 从原理聊JVM(四):JVM中的方法调用原理
    1引言多态是Java语言极为重要的一个特性,可以说是Java语言动态性的根本,那么线程执行一个方法时到底在内存中经历了什么,JVM又是如何确定方法执行版本的呢?2栈帧JVM中由栈帧存储方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法的调用就是从入栈到出栈到过......
  • 国产MCU-CW32F030开发学习-圆形GC9A01_LCD模块
    国产MCU-CW32F030开发学习-圆形GC9A01_LCD模块硬件平台CW32_48F大学计划板CW32_IOT_EVA物联网开发评估套件1.28寸圆形彩色TFT显示屏高清IPS模块240X240SPI接口GC9A01产品介绍1.28寸圆形IPS彩屏,支持RGB65K色显示,显示色彩丰富240X240分辨率,显示清晰IPS全视角面板,超宽可视范围采用......
  • springcloud 整合sentinel
    一、参考官网:Sentinel·alibaba/spring-cloud-alibabaWiki·GitHub1.搭建sentinelDashborad     1.下载jar包: Releases·alibaba/Sentinel(github.com)     2.启动:java-Dserver.port=8080-Dcsp.sentinel.dashboard.server=localhost:8080-......
  • 将Docker与DevOps文化结合:实现自动化、监控与日志管理
    引言:DevOps文化作为一种融合开发和运维的方法论,旨在加速软件交付和增强团队协作。而Docker作为一种轻量级、可移植的容器化技术,提供了快速部署和高度可扩展的解决方案。本文将深入探讨如何将Docker与DevOps文化结合,以实现自动化部署、高效监控和集中式日志管理,为现代软件开发与运维......
  • ELK日志分析系统
    目录一、ELK简介1.ElasticSearch2.Kiabana3.Logstash二、可添加的其它组件1.Filebeat2.filebeat结合logstash好处3.Fluentd三、为什么要使用ELK四、完整日志系统基本特征五、ELK的工作原理六、部署ELKElasticsearch集群环境七、部署ELKElasticsearch集群(在Node1......
  • 如何将 dubbo filter 拦截器原理运用到日志拦截器中?
    业务背景我们希望可以在使用日志拦截器时,定义属于自己的拦截器方法。实现的方式有很多种,我们分别来看一下。拓展阅读java注解结合springaop实现自动输出日志java注解结合springaop实现日志traceId唯一标识java注解结合springaop自动输出日志新增拦截器与过滤器......
  • P2568 GCD
    Question问题P2568GCD\[\sum_{p\inprime}\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)==p]\]Analysis分析1(所以肯定有第二种思考的方法,看后面(目前没写))变形\[\sum_{p\inprime}\sum_{i=1}^{\lfloor{\fracnp}\rfloor}\sum_{j=1}^{\lfloor{\fracnp}\rfloor}[\gcd(i,j)......