继上次将大数据查询改为分页查询或者流式查询后,系统在生产环境运行时Tomcat9仍然会持续出现内存每天都增加,tomcat无法回收=====还在内存溢出OOM中
于是继续将heap导出jmap -dump:format=b,file=heap.bin 5760
在MAT中分析,发现升级了dbcp2及log4j2后,log4j2在大内存中出现的次数比较多,而且在visualvm线程dump中发现很多
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000006c67a42f8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:123)
at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:33)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1113)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
由此查找log4j2 导致的Unsafe.park问题
在简书上看到Joker写的答案很完美,log4j2 的bug中有解决方案solution
其中log4j官网也做了详细说明:
The Long Story
The Log4j 2 Web JAR file is a web-fragment configured to order before any other web fragments in your application. It contains a ServletContainerInitializer
(Log4jServletContainerInitializer) that the container automatically discovers and initializes. This adds the Log4jServletContextListener and Log4jServletFilter to the ServletContext
. These classes properly initialize and deinitialize the Log4j configuration.
For some users, automatically starting Log4j is problematic or undesirable. You can easily disable this feature using the isLog4jAutoInitializationDisabled
context parameter. Simply add it to your deployment descriptor with the value "true" to disable auto-initialization. You must define the context parameter in web.xml
. If you set in programmatically, it will be too late for Log4j to detect the setting.
- <context-param>
- <param-name>isLog4jAutoInitializationDisabled</param-name>
- <param-value>true</param-value>
- </context-param>
Once you disable auto-initialization, you must initialize Log4j as you would a Servlet 2.5 web application. You must do so in a way that this initialization happens before any other application code (such as Spring Framework startup code) executes.
You can customize the behavior of the listener and filter using the log4jContextName
, log4jConfiguration
, and/or isLog4jContextSelectorNamed
context parameters. Read more about this in the Context Parameters section below. You must not manually configure the Log4jServletContextListener
or Log4jServletFilter
in your deployment descriptor (web.xml
) or in another initializer or listener in a Servlet 3.0 or newer application unless you disable auto-initialization with isLog4jAutoInitializationDisabled
. Doing so will result in startup errors and unspecified erroneous behavior.
关闭tomcat时 log4j2 报错: sun.misc.Unsafe.park(Native Method) - 简书
[LOG4J2-1259] Log4j threads are leaking on Tomcat shutdown - ASF JIRA