简体   繁体   English

关于在 Spring Boot 启动时引发异常时的 log4j2 内存泄漏

[英]About log4j2 memory leak when I raise an exception at spring boot starting

env:环境:
spring boot 1.5.9.RELEASE弹簧靴 1.5.9.RELEASE
spring-boot-starter-log4j2 ( Is Log4j 2.7 version ) spring-boot-starter-log4j2 ( 是 Log4j 2.7 版本)

All output information size is 9KB, including all spring boot output所有输出信息大小为9KB,包括所有spring boot输出

And this is my log4j2.xml config:这是我的 log4j2.xml 配置:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>

    <Properties>
        <Property name="pid">???</Property>


        <Property name="logPattern">%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:pid}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%xwEx</Property>


        <Property name="fileLogPattern">%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n\n</Property>


        <Property name="logPath">/data/server/tomcat/logs/bbPurchaseAgency</Property>

        <!-- for SizeBasedTriggeringPolicy, this is the problem, but I need file split function -->
        <Property name="fileSplitSize">2KB</Property>


        <Property name="fileSplitTime">1</Property>

        <Property name="maxSurviveTime">30d</Property>
    </Properties>

    <Appenders>
        <Console name="developLog" target="SYSTEM_OUT" follow="true">
            <PatternLayout charset="${encoding}" pattern="${logPattern}"/>
            <ThresholdFilter level="info" onMatch="accept" onMismatch="deny"/>
        </Console>


        <RollingFile name="infoFile" fileName="${logPath}/bbPurchaseAgency_info.log"
                     filePattern="${logPath}/bbPurchaseAgency_info_%d{yyyy-MM-dd}-%i.log">
            <PatternLayout charset="${encoding}" pattern="${fileLogPattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="${fileSplitTime}"/>
                <SizeBasedTriggeringPolicy size="${fileSplitSize}"/>
            </Policies>
            <Filters>

                <!-- this filter will be print all information whatever level it is -->
                <ThresholdFilter level="info" onMatch="accept" onMismatch="deny"/>
                <ThresholdFilter level="error" onMatch="deny" onMismatch="neutral"/>
                <ThresholdFilter level="warn" onMatch="deny" onMismatch="neutral"/>
            </Filters>
            <DefaultRolloverStrategy>
                <Delete basePath="${logPath}" maxDepth="1">
                    <IfFileName glob="bbPurchaseAgency_info_%d{yyyy-MM-dd}-%i.log" />
                    <IfLastModified age="${maxSurviveTime}"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>


        <RollingFile name="warnFile" fileName="${logPath}/bbPurchaseAgency_warn.log"
                     filePattern="${logPath}/bbPurchaseAgency_warn_%d{yyyy-MM-dd}-%i.log">
            <PatternLayout charset="${encoding}" pattern="${fileLogPattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="${fileSplitTime}"/>
                <SizeBasedTriggeringPolicy size="${fileSplitSize}"/>
            </Policies>
            <Filters>

                <ThresholdFilter level="error" onMatch="deny" onMismatch="neutral"/>
                <ThresholdFilter level="warn" onMatch="accept" onMismatch="deny"/>
            </Filters>
            <DefaultRolloverStrategy>
                <Delete basePath="${logPath}" maxDepth="1">
                    <IfFileName glob="bbPurchaseAgency_warn_%d{yyyy-MM-dd}-%i.log" />
                    <IfLastModified age="${maxSurviveTime}"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>


        <RollingFile name="errorFile" fileName="${logPath}/bbPurchaseAgency_error.log"
                     filePattern="${logPath}/bbPurchaseAgency_error_%d{yyyy-MM-dd}-%i.log">
            <PatternLayout charset="${encoding}" pattern="${fileLogPattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="${fileSplitTime}"/>
                <SizeBasedTriggeringPolicy size="${fileSplitSize}"/>
            </Policies>
            <Filters>

                <ThresholdFilter level="error" onMatch="accept" onMismatch="deny"/>
            </Filters>
            <DefaultRolloverStrategy>
                <Delete basePath="${logPath}" maxDepth="1">
                    <IfFileName glob="bbPurchaseAgency_error_%d{yyyy-MM-dd}-%i.log" />
                    <IfLastModified age="${maxSurviveTime}"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
    </Appenders>

    <Loggers>
        <AsyncLogger name="com.baibu.purchaseAgency" level="info" includeLocation="false">
            <AppenderRef ref="infoFile"/>
        </AsyncLogger>

        <AsyncLogger name="com.baibu.purchaseAgency" level="warn" includeLocation="true">
            <AppenderRef ref="warnFile"/>
        </AsyncLogger>

        <AsyncLogger name="com.baibu.purchaseAgency" level="error" includeLocation="true">
            <AppenderRef ref="errorFile"/>
        </AsyncLogger>

        <Root level="info">
            <AppenderRef ref="developLog"/>
            <AppenderRef ref="infoFile"/>
            <AppenderRef ref="warnFile"/>
            <AppenderRef ref="errorFile"/>
        </Root>
    </Loggers>
</Configuration>

So, here is the question:那么,问题来了:

When I active spring boot and testing by raise an exception, log4j2 print something, and trigger an exception what i design, AND THEN spring boot can not stop because log4j2 memory leak.当我激活 spring boot 并通过引发异常进行测试时,log4j2 打印一些东西,并触发我设计的异常,然后 spring boot 无法停止,因为 log4j2 内存泄漏。

This is the test code:这是测试代码:

@Value( "${spring.datasource.url}" )
    public void checkDataSource( String url ) {
        logger.warn( "warning url" );
        logger.error( "error url" );
        Integer.parseInt( url );  // I raise an exception when spring boot starting
    }

And this is stack info:这是堆栈信息:

The web application [ROOT] appears to have started a thread named [Log4j2-TF-4-1a752144-3] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
 java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
 java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:359)
 java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:942)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 java.lang.Thread.run(Thread.java:745)

And I run other test, like closing file split function( set fileSplitSize to 512MB ), or do this:我运行其他测试,比如关闭文件拆分功能(将 fileSplitSize 设置为 512MB),或者执行以下操作:

    @Value( "${spring.datasource.url}" )
    public void checkDataSource( String url ) {
    new Thread( new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep( 10 * 1000 );

            } catch ( InterruptedException e ) {
                e.printStackTrace();
            }

            System.exit( 0 );
        }
    } ).start();
}

Nothing happen, all good, no memory leak....什么都没有发生,一切都很好,没有内存泄漏......

Also I see this description on log4j2 web site( http://logging.apache.org/log4j/2.x/manual/webapp.html ):我也在 log4j2 网站( http://logging.apache.org/log4j/2.x/manual/webapp.html )上看到了这个描述:

To avoid problems the Log4j shutdown hook will automatically be disabled when the log4j-web jar is included.为避免出现问题,当包含 log4j-web jar 时,将自动禁用 Log4j 关闭挂钩。

I did it, but not working.我做到了,但没有工作。

Log4j2's gitHub has no issues plate, and there are little information about log4j2 memory leak on the web, can someone give me some idea to solve this ? Log4j2 的 gitHub 没有问题板块,网络上关于 log4j2 内存泄漏的信息很少,有人可以给我一些解决方法吗? THANK YOU VERY MUCH!非常感谢!

<context-param>
    <!-- auto-shutdown stops log4j when the web fragment unloads, but that
         is too early because it is before the listeners shut down. To 
         compensate, use a Log4jShutdownOnContextDestroyedListener and
         register it before any other listeners which means it will shut
         down *after* all other listeners. -->
    <param-name>isLog4jAutoShutdownDisabled</param-name>
    <param-value>true</param-value>
</context-param>    

<listener>
   <!-- ensure logging stops after other listeners by registering
        the shutdown listener first -->
    <listener-class>
       org.apache.logging.log4j.web.Log4jShutdownOnContextDestroyedListener
    </listener-class>
</listener>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM