Log4j2 Garbage-free 无垃圾回收模式实践与总结
Log4j2 内置 Garbage-free(无垃圾)模式,可重用对象和缓冲区,减少日志记录时产生的垃圾对象,避免 JVM 进行 GC 回收,进而提升应用程序的性能与响应速度。以下以 Log4j2 的 2.24.3 版本为基础,客观、真实、全面地介绍 Garbage-free 无垃圾回收模式,并总结其特性和应用场景。
先说结论: Log4j2 的 Garbage-free 无垃圾回收模式在实际使用中支持和适用场景极为有限,意义不大,不建议开启。
一、如何启用
默认情况下,Log4j2 根据应用是否为 Web 类型(通过判断 classpath 中是否包含 Servlet 类)来决定是否启用 Garbage-free 运行模式。若是 Web 应用,不开启,此时 log4j2.isWebapp 和 log4j2.enableThreadlocals 属性值分别为 true 和 false;反之,可将两属性值设置为 false 和 true,则强制开启 Garbage-free 模式。
在 Web 应用中,若 ThreadLocal 变量持有非 JDK 类,且 Web 应用程序卸载后,应用服务器的线程池仍继续引用这些变量,可能导致应用内存泄漏。因此,为避免内存泄漏,Web 应用默认不开启 Garbage-free 模式。Web 应用可通过强制指定 log4j2.enableThreadlocals=true 来开启该模式。此外,若使用线程上下文字段(如 MDC),还需将 log4j2.garbagefreeThreadContextMap 属性设为 true。
建议将上述配置属性统一放在类路径(通常是 src/main/resources/)下的 log4j2.component.properties 文件中。这种配置方式可被 JVM 变量、系统环境变量和编码覆盖。
二、配套要求
启用 Garbage-free 模式(log4j2.enableThreadlocals 属性值设置为 true)后,需配套使用支持 Garbage-free 的 Layouts、Appenders 和 Filters,并合理使用 API,才能确保该模式真正生效。
1. 支持的 Layout
(1)有条件支持 GelfLayout、JsonTemplateLayout 和 PatternLayout 这三种 Layout,不支持常用的 CsvLayout。
(2)上述三种 Layout 并非完全支持。如果其中使用了不支持 Garbage-free 的参数、配置或方法,会导致该 Layout 不支持 Garbage-free。例如,在 PatternLayout 中输出 Exception、Method、Line、Location、Class、File 等字段,就会使得该 Layout 不支持 Garbage-free。
2. 支持的 Appender
(1)ConsoleAppender 及文件类 Appender,如 FileAppender、MemoryMappedFileAppender、RandomAccessFileAppender、RollingFileAppender(非轮转期间)、RollingRandomAccessFileAppender(非轮转期间)均支持。
(2)大部分涉及外部 IO(网络、数据库和消息队列等)的 Appender 均不支持,例如 JDBCAppender、KafkaAppender 等。
(3)上述结论仅源于官方文档,未经详细测试。总结 Layout 使用经验,建议仔细参考各 Appender 文档,判断是否存在具体限制。
3. 支持的 Filter
(1)CompositeFilter、DynamicThresholdFilter、LevelRangeFilter、MapFilter、MarkerFilter、StructuredDataFilter、ThreadContextMapFilter、ThresholdFilter 和 TimeFilter 均支持。
(2)上述结论仅源于官方文档,未经详细测试。总结 Layout 使用经验,建议仔细参考各 Appender 文档,判断是否存在具体限制。
4. 其他情况
(1)如果使用了 NDC(Nested Diagnostic Context),则无法支持 Garbage 模式。
(2)异步日志(AsyncLogger)如果使用默认的 timeout 等待策略,则支持 Garbage 模式。
(3)从测试情况来看,即便使用的 Layout、Appender 和 Filter 都支持 Garbage 模式,但如果 logger 输出内容包不支持 Garbage 模式的字段,最终也无法使用 Garbage 模式。
三、强烈建议
在实际项目中,即便应用启用 Garbage 模式,受各种使用限制和配置要求影响,实际也未必真正启用。强烈建议使用 JMH 对相应的日志配置进行压测,并添加“prof gc”参数,以验证 GC 的回收情况,从而判断该日志配置是否真正支持 Garbage 模式。
四、性能对比
以下我们将使用相同的性能测试基准,通过配置参数强制开启或关闭 Garbage 模式,以此判断该模式对性能的帮助。
1. 测试基准
(1)硬件:Windows 笔记本,配置为 I5-1350P CPU、32G DDR5 5200 内存以及三星 MZVL4512HBLU-00BLL 512G SSD(顺序写入速度为 2430MB/s)。
(2)软件:基于 JDK 1.8.171,使用 1.37 版 JMH 和 2.24.3 版 Log4j2。
(3)配置:采用 FileAppender 及其默认配置(append 和 immediateFlush 均为 true),使用同步 Logger 进行压测。
(4)参考日常使用情况,输出长度为 100 个的固定字符串,日志 PatternLayout 布局为:“% d {yyyy-MM-dd HH:mm:ss.SSS} %-5level % pid % t - % msg % n”。
(5)在 classpath 下添加 log4j2.component.properties 配置文件,通过 log4j2.enableThreadlocals 配置项来开启或关闭 Garbage-free 模式。
2. Log4j2 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="log4j2AppenderTest" status="error">
<Properties>
<Property name="log.pattern">
%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %pid %t - %msg %n
</Property>
</Properties>
<Appenders>
<Console name="Console">
<PatternLayout pattern="${log.pattern}"/>
</Console>
<File name="File"
fileName="log/log4j2-file.log">
<PatternLayout pattern="${log.pattern}"/>
</File>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
<Logger name="FileLogger" level="debug" additivity="false">
<AppenderRef ref="File" />
</Logger>
</Configuration>
3. JMH 压测代码
@State(Scope.Benchmark)
public class Log4J2FileAppenderBenchmark {
static Logger fileLogger;
int delFilesCount = 0;
@Setup(Level.Trial)
public void setUp() throws Exception {
System.setProperty("log4j.configurationFile", "log4j2.xml");
fileLogger = LogManager.getLogger("FileLogger");
}
@TearDown
public void tearDown() {
System.clearProperty("log4j.configurationFile");
}
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Benchmark
public void fileLogger() {
fileLogger.debug(Const.MSG_HAVE_100_CHARS);
}
}
4. JMH 参数
JMH 执行的参数为:-jvmArgs "-Xmx512m -Xms512m" -f 2 -t 4 -w 10 -wi 2 -r 30 -i 2 -to 300 -prof gc,即设置 JVM 参数为 -Xmx512m -Xms512m(堆内存最大和最小均为 512MB),使用 2 个 fork(-f 2),每个 fork 使用 4 个线程(-t 4),预热阶段每次运行 10 秒(-w 10),预热迭代 2 次(-wi 2),正式测试每次运行 30 秒(-r 30),正式测试迭代 2 次(-i 2),超时时间为 300 秒(-to 300),并启用 GC 性能分析(-prof gc)。
5. 测试结果
| 类型 | 平均吞吐量 | 内存分配速率(MB/sec) | 垃圾回收次数 |
|---|---|---|---|
| Garbage-free 模式 | 137.1 ops/ms | 10 MB/sec | 0 |
| 非 Garbage-free 模式 | 135.5 ops/ms | 18.8 MB/sec | 18 |
6. 测试总结
(1)由于不少 PatternLayout 参数不支持无垃圾回收模式,因此上述 PatternLayout 配置参数略微简单,在相同配置下,启用 Garbage-free 模式后,内存分配量明显下降,且无 GC 回收及耗时,但吞吐量并无明显提高。
(2)此外,经其他测试发现,越不支持无垃圾回收模式的参数,越占内存,如输出日志所在的类、方法、行数及完整异常堆栈信息等。
五、总结
在日常研发中,我们主要将 Log4j2 用于 Web 开发,默认不开启 Garbage-free 模式。若强制启用,一旦使用不当,可能导致内存泄露。即便强制启用,实际使用时,各类日志输出字段需包含产生日志的类、方法、行数及完整异常堆栈等基本字段,而这些字段又不支持 Garbage-free 模式,仍会产生垃圾回收,最终真正启用该模式。所以我认为,Log4j2 的 Garbage-free 无垃圾回收模式在实际使用中支持和适用场景极为有限,意义不大,不建议开启。
六、参考文档
Log4j2 Garbage-free 无垃圾回收模式实践与总结的更多相关文章
- 2.5 – Garbage Collection 自动垃圾回收 Stop-the-world vs. incremental vs. concurrent 垃圾回收策略
2.5 – Garbage Collection 自动垃圾回收 Lua 5.3 Reference Manual http://www.lua.org/manual/5.3/manual.html# ...
- GC(Garbage Collection)垃圾回收机制
1.在垃圾回收器中,程序员没有执行权,只有通知它的权利. 2.程序员可以通过System.gc().通知GC运行,但是Java规范并不能保证立刻运行. 3.finalize()方法,是java提供给程 ...
- python 之gc(回收机制)--garbage collection(GC垃圾回收)
######################引用计数######################### 引用计数:python 当中一种用来解决垃圾回收的策略之一 char 1个字节(2**8) in ...
- [Java] 垃圾回收机制 ( Garbage Collection ) 简介
自动垃圾回收( Automatic Garbage Collection ) 自动垃圾回收,是指在堆(Heap)内存上分辨哪些对象还在被使用,哪些对象没有被使用,并清除没有被使用的对象.所以,这里的垃 ...
- 【python进阶】Garbage collection垃圾回收1
前言 GC垃圾回收在python中是很重要的一部分,同样我将分两次去讲解Garbage collection垃圾回收,此篇为Garbage collection垃圾回收第一篇,下面开始今天的说明~~~ ...
- 【python进阶】Garbage collection垃圾回收2
前言 在上一篇文章[python进阶]Garbage collection垃圾回收1,我们讲述了Garbage collection(GC垃圾回收),画说Ruby与Python垃圾回收,Python中 ...
- Java进阶 JVM 内存与垃圾回收篇(一)
JVM 1. 引言 1.1 什么是JVM? 定义 Java Vritual Machine - java 程序的运行环境(Java二进制字节码的运行环境) 好处 一次编译 ,到处运行 自动内存管理,垃 ...
- Chrome 浏览器垃圾回收机制与内存泄漏分析
Chorme 浏览器中的垃圾回收和内存泄漏 垃圾回收 通常情况下,垃圾数据回收分为手动回收和自动回收两种策略. 手动回收策略,何时分配内存.何时销毁内存都是由代码控制的. 自动回收策略,产生的垃圾数据 ...
- JVM 专题二十一:垃圾回收(五)垃圾回收器 (二)
3. 回收器 3.1 Serial回收器:串行回收 3.1.1 概述 Serial收集器是最基本.历史最悠久的垃圾收集器了.JDK1.3之前回收新生代唯一的选择. Serial收集器作为Hotspot ...
- Java垃圾回收机制详解
前言 Java 相比 C/C++ 最显著的特点便是引入了自动垃圾回收 (下文统一用 GC 指代自动垃圾回收),它解决了 C/C++ 最令人头疼的内存管理问题,让程序员专注于程序本身,不用关心内存回收这 ...
随机推荐
- 一种小资源情况下RDS数据实时同步StarRocks方案
一.背景 目前需要将阿里云RDS数据库的数据同步到自建的StarRocks集群.之前使用DolphinScheduler通过定时调度Datax任务,将数据同步到StarRocks集群中,但是随着业务的 ...
- Filter内存马
概述 最近感冒了,不想BB太多,直接开始调试吧,先写个Filter来调试 Filter代码 新建一个FilterShell类,代码如下: 一个类如果想要成为Filter则需要继承Filter,然后重写 ...
- WinForm 开源组件 Realtiizor
Realtiizor 的优势 现代美观的界面设计 Realtiizor 为 WinForm 应用带来了现代感十足的界面风格.它采用了流行的设计理念,如 Material Design 的元素融入,使得 ...
- Kettle连接MySQL数据库时提示Driver class 'org.gjt.mm.mysql.Driver' could not be found
使用Kettle连接MySQL数据库时,提示以下连接提示信息导致我们无法对数据库进行连接: Driver class 'org.gjt.mm.mysql.Driver' could not be fo ...
- 数据分层 ODS DW DM层级
在数据仓库的设计过程中,数据分层是一种重要的组织方式,能够提高数据处理效率和数据质量.数据分层通常包括原始数据(Operational Data Store,ODS).明细数据(Data Wareho ...
- .NET周刊【12月第2期 2024-12-08】
国内文章 终于解决了.net在线客服系统总是被360误报的问题(对软件进行数字签名) https://www.cnblogs.com/sheng_chao/p/18581139 升讯威在线客服与营销系 ...
- 基于知识图谱的医疗问答系统(dockerfile+docker-compose)
目录 一.搭建 Neo4j 图数据库 1.方式选择 2.Dockerfile+docker-compose部署neo4j容器 2.1.更新 yum 镜像源 2.2.安装 docker-ce 社区版 2 ...
- vue3 重置reactive数据
有一个formData数据字段,使用class创建一份初始数据与其对应,使用Object.assign进行重置 import { reactive } from 'vue' class InitFor ...
- Could not retrieve transation read-only status server 的解决办法
问题描述: 在项目开发的过程中,使用Hibernate的ORM进行建表时,出现 " Could not retrieve transation read-only status server ...
- 【FAQ】HarmonyOS SDK 闭源开放能力 — IAP Kit(4)
1.问题描述: 发布了一个订阅,看日志显示订阅发布成功了,但是在消费的时候没有值,这个是什么原因?人脸活体检测返回上一页 App 由沉浸式变为非沉浸式多了上下安全区域. 解决方案: 对于公共事件来说就 ...