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 无垃圾回收模式在实际使用中支持和适用场景极为有限,意义不大,不建议开启。

六、参考文档

(1)log4j2.x garbagefree

Log4j2 Garbage-free 无垃圾回收模式实践与总结的更多相关文章

  1. 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# ...

  2. GC(Garbage Collection)垃圾回收机制

    1.在垃圾回收器中,程序员没有执行权,只有通知它的权利. 2.程序员可以通过System.gc().通知GC运行,但是Java规范并不能保证立刻运行. 3.finalize()方法,是java提供给程 ...

  3. python 之gc(回收机制)--garbage collection(GC垃圾回收)

    ######################引用计数######################### 引用计数:python 当中一种用来解决垃圾回收的策略之一 char 1个字节(2**8) in ...

  4. [Java] 垃圾回收机制 ( Garbage Collection ) 简介

    自动垃圾回收( Automatic Garbage Collection ) 自动垃圾回收,是指在堆(Heap)内存上分辨哪些对象还在被使用,哪些对象没有被使用,并清除没有被使用的对象.所以,这里的垃 ...

  5. 【python进阶】Garbage collection垃圾回收1

    前言 GC垃圾回收在python中是很重要的一部分,同样我将分两次去讲解Garbage collection垃圾回收,此篇为Garbage collection垃圾回收第一篇,下面开始今天的说明~~~ ...

  6. 【python进阶】Garbage collection垃圾回收2

    前言 在上一篇文章[python进阶]Garbage collection垃圾回收1,我们讲述了Garbage collection(GC垃圾回收),画说Ruby与Python垃圾回收,Python中 ...

  7. Java进阶 JVM 内存与垃圾回收篇(一)

    JVM 1. 引言 1.1 什么是JVM? 定义 Java Vritual Machine - java 程序的运行环境(Java二进制字节码的运行环境) 好处 一次编译 ,到处运行 自动内存管理,垃 ...

  8. Chrome 浏览器垃圾回收机制与内存泄漏分析

    Chorme 浏览器中的垃圾回收和内存泄漏 垃圾回收 通常情况下,垃圾数据回收分为手动回收和自动回收两种策略. 手动回收策略,何时分配内存.何时销毁内存都是由代码控制的. 自动回收策略,产生的垃圾数据 ...

  9. JVM 专题二十一:垃圾回收(五)垃圾回收器 (二)

    3. 回收器 3.1 Serial回收器:串行回收 3.1.1 概述 Serial收集器是最基本.历史最悠久的垃圾收集器了.JDK1.3之前回收新生代唯一的选择. Serial收集器作为Hotspot ...

  10. Java垃圾回收机制详解

    前言 Java 相比 C/C++ 最显著的特点便是引入了自动垃圾回收 (下文统一用 GC 指代自动垃圾回收),它解决了 C/C++ 最令人头疼的内存管理问题,让程序员专注于程序本身,不用关心内存回收这 ...

随机推荐

  1. JPEG格式研究——(4)反量化、逆ZigZag变化和IDCT变换

    反量化 反量化其实很简单,将霍夫曼解码出来的数据乘上对应的量化表就好了 通过当前色度选择出SOF中的Component,其中的Tqi指出了这一色度所需的量化表id Component的结构如下: 名称 ...

  2. PythonDay2Base

    PythonDay2Base 前文见上一篇文章 数据类型详解 字符串 str 补充 startswith 判断字符串是否以某个小字符串开头 s1 = "shujia数加科技学习study&q ...

  3. javascript 实现参数重载

    1.概要 在java中,同一个函数签名,比如 getUser,我们可以根据参数的不同,调用不同功能的方法.这也就是参数重载,如何在javascript也实现参数重载呢? 2.实现方法 function ...

  4. Spring完全注解开发

    注解的好处:如果管理很多的Bean,要求这些Bean都配置在applocationContext.xml文件中.用了注解之后,就不需要在xml文件中配置了,Spring提供了几个辅助类会自动扫描和装配 ...

  5. Docker学习笔记(一) - Docker安装

    1.安装yum-utils yum install yum-utils device-mapper-persistent-data lvm2 复制 安装yum-utils是为方便添加yum源使用的,d ...

  6. shell中 ${}, ##, %%, :-,:+, ? 的使用

    假设我们定义了一个变量为:file=/dir1/dir2/dir3/my.file.txt 可以用${}分别替换得到不同的值:${file#*/} 删掉第一个/及其左边的字符串:dir1/dir2/d ...

  7. Anaconda中的Spyder软件设置为中文教程

     Anaconda中的Spyder软件设置为中文教程 第一步:工具栏中Tools --> Preferences 第二步:第二栏的 Application--> 第二个选项卡Advance ...

  8. Qt编写的项目作品28-视频监控显示安卓版

    一.功能特点 1.1 基础功能 支持各种音频视频文件格式,比如mp3.wav.mp4.asf.rm.rmvb.mkv等. 支持各种视频流格式,比如rtp.rtsp.rtmp.http等. 本地音视频文 ...

  9. WorldWind源码剖析系列:WorldWind瓦片调度策略说明

    1 基于源码的分析 首先我们来看WorldWind中摄像头变化相关的几个方法的内部逻辑. 1.1 NltTerrainAccessor. GetElevationAt 方法声明:public over ...

  10. 架构-初识DDD

    引言 继上一篇BFF的文章后,我又去网上学习了一下DDD(领域驱动设计),发现一篇不错的文章,参考并写了一些自己的理解分享在这里. DDD 是什么 领域驱动设计(Domain Driven Desig ...