添加SLF4J依赖后Swing应用卡顿严重,该从何处排查?
问题背景
仅添加SLF4J依赖后,我的Swing应用变得异常卡顿。
规范日志实现前的状态
此前我使用java.util.Logger输出日志,部分日志甚至直接用System.out.println打印。
Log4j2/SLF4J配置过程
之后我添加了Log4j2的Maven依赖,并在src/main/resources目录下放置了log4j2.xml,但由于仍在向java.util.Logger写入日志,配置未生效。
我了解到需要从Log4j的LogManager获取Logger,或者为了更好的可配置性,从SLF4J的LoggerFactory获取Logger,以便后续客户端可以接入任意日志实现。
于是我开始通过SLF4J LoggerFactory获取Logger并写入日志。在Log4j2依赖和log4j2.xml配置到位后,日志功能正常,仅我设置为DEBUG级别的包会输出日志。
性能问题出现
一切看似正常,除了性能!我的应用CPU占用率达125%,导致MacBook Pro发热。而MBP存在发热后kernel_task进程CPU占用率几分钟内飙升至500%的问题。
简而言之,修复日志配置后,我的应用变得无法使用。
移除Classpath中的Log4j2
不仅如此,我甚至移除了Log4j2依赖,日志停止输出。仅保留SLF4J,仍通过SLF4J LoggerFactory获取Logger写入日志,但应用CPU占用率仍达125%,MBP的kernel_task进程进而导致系统冻结。
问题出在哪里?SLF4J存在内存泄漏?还是Java Swing向SLF4J写入了过多日志?
初步排查计划
- 将SLF4J升级至适配Java 1.8的最新版本
- 弃用SLF4J,直接写入Log4j2
- 回退至
java.util.Logger
配置文件补充
以下是我使用的log4j2.xml配置(注:移除Log4j2依赖后,日志已停止输出):
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="warn" name="tradez" packages=""> <Appenders> <Console name="app_stdout" target="SYSTEM_OUT"> <!-- PatternLayout pattern="%date{HH:mm:ss,SSS} %t %-5level %class{1.}:%method:: %message %n" / --> <PatternLayout pattern="%date %t %-5level %message %n" /> </Console> </Appenders> <Loggers> <Logger name="net.progressit.tradez" level="debug"> <AppenderRef ref="app_stdout" /> </Logger> <Root level="info"> <AppenderRef ref="app_stdout" /> </Root> </Loggers> </Configuration>
依赖澄清
有趣的是,即使我从Maven中移除Log4j2依赖并清理项目后,仍收到来自Log4j2的提示信息:ERROR StatusLogger Log4j2 could not find a logging implementation。
后来发现是我理解有误,我的pom.xml中仅包含以下日志相关依赖:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.7</version> </dependency>
我并未引入纯SLF4J,仅引入了log4j-slf4j-impl,这正是我收到特定错误提示的原因。
问题解决
按照建议,我使用JVisualVM调试应用性能,发现有一个线程一直在持续重新布局组件,最终停在getFontMetrics方法。看来MigLayout的布局从未稳定,即使程序未对UI做任何更改,仍会持续重新布局。
于是我将MigLayout依赖从5.2版本(2018年)升级至11版本(2021年最新版),CPU占用率从150%降至1.5%。
![JVisualVM性能分析截图]
内容的提问来源于stack exchange,提问作者Teddy

