Java虚拟机之 XX:+UseGCLogFileRotation 解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 通常,在生产环境中,我们需要借助 GC Log 来实时检测我们的微服务基于 Java 虚拟机层面活动状态,涉及年轻代、年老代以及全局的垃圾回收 ,只有基于上述方案,我们才能够快速的定位、分析微服务在某一时刻、时间段所呈现的活动轨迹及事件,以便高效解决业务问题。此篇文章来自笔者早期博客,依据实际的项目场景进行总结整理的。因技术群里有朋友在问此方面领域的问题,故再次将其呈现出来。

    通常,在生产环境中,我们需要借助 GC Log 来实时检测我们的微服务基于 Java 虚拟机层面活动状态,涉及年轻代、年老代以及全局的垃圾回收 ,只有基于上述方案,我们才能够快速的定位、分析微服务在某一时刻、时间段所呈现的活动轨迹及事件,以便高效解决业务问题。此篇文章来自笔者早期博客,依据实际的项目场景进行总结整理的。因技术群里有朋友在问此方面领域的问题,故再次将其呈现出来。

    首先,我们来看一下在实际的生产环境中,应用服务中是如何开启日志打印相关开关,具体示例可参考如下所示:


JAVA_OPTS="-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/data/logs/adminMana/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 -XX:GCLogFileSize=512k"

      上述参数为 JDK 9 之前,尤其是 JDK 6/8 的通用型 GC Log 启用参数,针对  JDK 9 之后,以 JDK 11 为例,可尝试通过以下命令行参数启用,具体如下所示:


-Xlog:gc*,gc+ref=debug,gc+age=trace,gc+heap=debug:file=gc%p%t.log:tags,uptime,time:filecount=10,filesize=10m

    本文暂不解析 JDK 11 版本的相关日志规范及相关案例,后续文章将会给出。现在针对 JDK 9 之前版本的核心日志参数进行简要解析,以让大家能够了解下相关参数的作用及场景特点,具体如下:

1、-XX:+PrintGCDetails

        此参数主要定义GC Log 的详细信息。

2、-XX:+PrintGCTimeStamps

        此参数主要定义GC Log 的时间戳信息,通常以“基准时间”形式打印。

3、-Xloggc:/data/logs/adminMana/gc.log

        此参数主要定义GC Log 的存储路径以及所输出的文件名称。

4、-XX:+UseGCLogFileRotation

        此参数主要定义GC Log 的滚动功能,需要进行开启或关闭,其通常基于第3条的    

    -Xloggc 参数展开。

5、-XX:NumberOfGCLogFiles=3

        此参数主要定义滚动日志文件的个数,此参数值必须大于等于1,对应的日志文件

    命名策略为:.0、.1、 ... 、 .n-1等,其中 n 是  

    该参数的值。

6、-XX:GCLogFileSize=512k

        此参数主要定义滚动日志文件的大小,必须大于 8k,当前写日志文件大小超过该    

    参数值时,日志将写入下一个文件,依次类推。

    具体,我们来看一下简单的 GC Log 输出的示例,如下所示:


[administrator@JavaLangOutOfMemory cpu ]% less devopsDemo.log.0.current
Java HotSpot(TM) 64-Bit Server VM (25.271-b09) for bsd-amd64 JRE (1.8.0_271-b09), built on Sep 16 2020 16:54:38 by "java_re" with gcc 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)
Memory: 4k page, physical 4194304k(27404k free)
/proc/meminfo:
CommandLine flags: -XX:GCLogFileSize=524288 -XX:InitialHeapSize=67108864 -XX:MaxHeapSize=1073741824 -XX:NumberOfGCLogFiles=3 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseGCLogFileRotation -XX:+UseParallelGC 
Heap
 PSYoungGen      total 18944K, used 1311K [0x00000007aab00000, 0x00000007ac000000, 0x00000007c0000000)
  eden space 16384K, 8% used [0x00000007aab00000,0x00000007aac47cb0,0x00000007abb00000)
  from space 2560K, 0% used [0x00000007abd80000,0x00000007abd80000,0x00000007ac000000)
  to   space 2560K, 0% used [0x00000007abb00000,0x00000007abb00000,0x00000007abd80000)
 ParOldGen       total 44032K, used 0K [0x0000000780000000, 0x0000000782b00000, 0x00000007aab00000)
  object space 44032K, 0% used [0x0000000780000000,0x0000000780000000,0x0000000782b00000)
 Metaspace       used 2731K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 291K, capacity 386K, committed 512K, reserved 1048576K

   上面的 GC 垃圾回收策略基于 JDK 1.8 ,采用默认指定的策略,从上述的简要的 GC Log ,我们可以看出当前的 Java 虚拟机基础环境信息、启动参数以及各个代的相关活动情况。

   通常,在我们开启 GC Log 文件后,日志文件的大小以及数量的分割有时候往往需要给予更多的关注,毕竟,无论从管理角度、信息完整性角度、友好性及其他相关联角度,都需要综合性考虑。因此,基于 -XX:+UseGCLogFileRotation 参数所定义的日志滚动功能,在大多数公司也应用,然而,在实际的生产环境中是否推荐呢?这也是本文所需要探讨的另一方面内容。

    其实,从生产落地场景来说,现在的日志采集、管理及存储框架比较成熟,比如,通过 Agent 将其存储至第三方系统,更有利于对其进行管理与维护。本文着重从应用日志处理角度,基于此参数 -XX:+UseGCLogFileRotation 的相关设置所引入的缺陷以及解决方案。那么,会带来哪些问题呢?具体如下:

1、内容丢失问题

    正如上述参数所描述的场景那样,假设,在我的微服务启动参数中显性定义了以下参数:-XX:+UseGCLogFileRotation、-XX:NumberOfGCLogFiles=3 以及 -XX:GCLogFileSize=20M ,即意味着我们设置了3个文件,应用程序运行一段时间过后就会生成3个日志文件,假如最先定义的是admin-gc.log.0,最近的是admin-gc.log.3,当admin-gc.log.3到达20M以后,日志会重新写入到admin-gc.log.0,admin-gc.log.0之前的内容会被清空掉,从而使得之前的信息不够完整。

2、可读性差

    还是基于上述相同场景,日志目录已生成3个日志文件:admin-gc.log.0 到 admin-gc.log.3,若此时因各种原因进行JVM重启操作,此时 GC Log 会重新从 admin- gc.log.0 开始写入,但是 admin-gc.log.1、admin-gc.log.2、admin-gc.log.3这里面的日志依然为之前旧的日志,新旧日志就混合写入,导致格式模糊,可读性较差,影响用户体验。因此,若要解决这个问题,在重启服务器之前我们需要把老的日志全部迁移到其他目录,以避免重启后日志重新写入问题,影响日志的可读性。

3、不易分析

    基于上述策略,若我们将 GC Log 进行分割后,生成的文件数量较多,通过日志分析平台(例如:类似GC Viewer及相关平台)进行解析时,往往需要导入多份文件,同时,由于各个文件( admin-gc.log.1、admin-gc.log.2、admin-gc.log.3、...)内容之间可能存在时间间断,故上传至分析平台的文件不够完整,导致分析出来的结果参考性意义不大,从而很难为具体的业务场景需求提供优化建议。

4、难以维护

    基于上述参数定义的场景,当前应用服务运行期间的活动日志文件的后缀名会被标记为 .current,假设,应用服务在某一时刻活动所生成的日志文件是 admin-gc.log.3,那么此时,其对应的活动日志文件名会被命名为 admin-gc.log.3.current,如果我们要把不同机器上的 GC Log 文件都集中传送至某一共享主机上去的话,通常我们会借助各种日志同步工具或命令行,例如:Rsyslog 等类似工具,然而,基于此种策略下的命名方式对 类似 Rsyslog 工具来说效率较为低下,影响数据的实时同步。

    综上4点所述为基于 -XX:+UseGCLogFileRotation 参数在 GC Log 分析、存储时所带来的弊端,当然,也有其他潜在的问题,本文暂不讨论。那么,针对如上问题,是否有较好的建议或意见呢?答案:当然有。而且很多,在这里,我们简要介绍 2 种参考方案,具体如下所示:

    1、对接至第三方日志系统

    若我们不对 GC Log 文件进行滚动操作,让其以原生态模式进行日志输出,然后将其转储至第三方日志系统,依据第三方日志系统定义的日志规范。即使我们的应用服务因各种原因进行重启操作,也不会影响 GC Log 的写入,从而避免数据的丢失。

    2、增加时间戳

   若我们想实现 GC Log 文件的切割,我们可以尝试在 GC Log 的文件后缀加上时间戳,当 JVM 重启以后,会生成新的日志文件,新的日志也不会覆盖老的日志,只需要在日志文件名中添加 %t的后缀即可,具体如下示例所示:


-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/logs/admin-gc-%t.log

    “%t” 将会在文件名添加时间戳后缀,其生成的通用格式为 YYYY-MM-DD_HH-MM-SS,例如:“admin-gc-2016-01-01_02-13-04.log” 。基于此种策略,我们就轻而易举地避免了基于 -XX:+UseGCLogFileRotation 参数带来的所有的困扰。当然,撇开应用服务本身的特性,如果基于日志切割,目前成熟的方案有很多种,无论是基于哪种,终极目标无非是性能损耗小、易分析、易维护,大家有兴趣的话,可以实践其他方案。

    至此,关于 Java 虚拟中 XX:+UseGCLogFileRotation 参数的相关解析本文到此为止,大家有什么疑问、想法及建议,欢迎留言沟通。

相关文章
|
15天前
|
缓存 Java 应用服务中间件
Java虚拟线程探究与性能解析
本文主要介绍了阿里云在Java-虚拟-线程任务中的新进展和技术细节。
|
13天前
|
设计模式 安全 Java
Java 编程中的设计模式:单例模式的深度解析
【9月更文挑战第22天】在Java的世界里,单例模式就像是一位老练的舞者,轻盈地穿梭在对象创建的舞台上。它确保了一个类仅有一个实例,并提供全局访问点。这不仅仅是代码优雅的体现,更是资源管理的高手。我们将一起探索单例模式的奥秘,从基础实现到高级应用,再到它与现代Java版本的舞蹈,让我们揭开单例模式的面纱,一探究竟。
23 11
|
6天前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
19 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
13天前
|
缓存 负载均衡 Dubbo
Dubbo技术深度解析及其在Java中的实战应用
Dubbo是一款由阿里巴巴开源的高性能、轻量级的Java分布式服务框架,它致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
39 6
|
9天前
|
监控 算法 Java
深入解析Java中的垃圾回收机制
本文旨在全面解析Java的垃圾回收机制,探讨其工作原理、常见算法以及在实际开发中的应用。通过对这一重要主题的深入分析,希望帮助读者更好地理解Java虚拟机(JVM)如何管理内存,从而编写出更高效、稳定的Java应用程序。
|
9天前
|
Java 开发者
Java中的异常处理机制深度解析
在Java编程中,异常处理是保证程序稳定性和健壮性的重要手段。本文将深入探讨Java的异常处理机制,包括异常的分类、捕获与处理、自定义异常以及一些最佳实践。通过详细讲解和代码示例,帮助读者更好地理解和应用这一机制,提升代码质量。
12 1
|
18天前
|
安全 Java 开发者
Java并发编程中的锁机制解析
本文深入探讨了Java中用于管理多线程同步的关键工具——锁机制。通过分析synchronized关键字和ReentrantLock类等核心概念,揭示了它们在构建线程安全应用中的重要性。同时,文章还讨论了锁机制的高级特性,如公平性、类锁和对象锁的区别,以及锁的优化技术如锁粗化和锁消除。此外,指出了在高并发环境下锁竞争可能导致的问题,并提出了减少锁持有时间和使用无锁编程等策略来优化性能的建议。最后,强调了理解和正确使用Java锁机制对于开发高效、可靠并发应用程序的重要性。
16 3
|
11天前
|
分布式计算 Java API
深入解析Java中的Lambda表达式及其应用
本文将深入探讨Java中Lambda表达式的定义、优势及其在实际编程中的应用。通过具体示例,帮助读者更好地理解和使用这一强大的编程工具。
|
2月前
|
Java Docker 索引
记录一次索引未建立、继而引发一系列的问题、包含索引创建失败、虚拟机中JVM虚拟机内存满的情况
这篇文章记录了作者在分布式微服务项目中遇到的一系列问题,起因是商品服务检索接口测试失败,原因是Elasticsearch索引未找到。文章详细描述了解决过程中遇到的几个关键问题:分词器的安装、Elasticsearch内存溢出的处理,以及最终成功创建`gulimall_product`索引的步骤。作者还分享了使用Postman测试接口的经历,并强调了问题解决过程中遇到的挑战和所花费的时间。
|
2月前
|
存储 算法 Oracle
不好意思!耽误你的十分钟,JVM内存布局还给你
先赞后看,南哥助你Java进阶一大半在2006年加州旧金山的JavaOne大会上,一个由顶级Java开发者组成的周年性研讨会,公司突然宣布将开放Java的源代码。于是,下一年顶级项目OpenJDK诞生。Java生态发展被打开了新的大门,Java 7的G1垃圾回收器、Java 8的Lambda表达式和流API…大家好,我是南哥。一个Java学习与进阶的领路人,相信对你通关面试、拿下Offer进入心心念念的公司有所帮助。
不好意思!耽误你的十分钟,JVM内存布局还给你

热门文章

最新文章

推荐镜像

更多
下一篇
无影云桌面