使用Hystrix关闭时的Spring Boot内存泄漏

时间:2019-07-18 04:06:58

标签: spring-boot memory-leaks hystrix shutdown-hook circuit-breaker

我有一个可以正常关闭Spring Boot应用程序的类。

@Configuration
public class GracefulShutdownConfig extends BaseObject {
private static Object lock = new Object();
private static boolean isPreventShutdown = false;

@Bean
public GracefulShutdown gracefulShutdown() {
    return new GracefulShutdown();
}

@Bean
public ConfigurableServletWebServerFactory webServerFactory(final GracefulShutdown gracefulShutdown) {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addConnectorCustomizers(gracefulShutdown);
    return factory;
}

public class GracefulShutdown extends BaseObject
        implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {

    @Value("${graceful.shutdown.eureka.client.timeout}")
    private long eurekaShutdownTimeout;

    @Value("${graceful.shutdown.rest.controller.wait.time.max}")
    private long restControllerWaitTimeMax;

    @Autowired
    private EurekaClient discoveryClient;

    private volatile Connector connector;

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        // TODO Auto-generated method stub
        logger.info("onApplicationEvent ContextClosedEvent");
        try {
            boolean needWaitEureka = false;
            synchronized (lock) {
                if(!isPreventShutdown) {
                    needWaitEureka = true;
                    isPreventShutdown = true;
                }
            }
            if(needWaitEureka) {                     
                discoveryClient.shutdown();
                Thread.sleep(eurekaShutdownTimeout);
            }
            this.connector.pause();
            Executor executor = this.connector.getProtocolHandler().getExecutor();
            if (executor instanceof ThreadPoolExecutor) {
                try {
                    ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                    threadPoolExecutor.shutdown();
                    if (!threadPoolExecutor.awaitTermination(restControllerWaitTimeMax, TimeUnit.SECONDS)) {
                        logger.error("Tomcat thread pool did not shut down gracefully within " + restControllerWaitTimeMax 
                                + " seconds. Proceeding with forceful shutdown");
                    }
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        } catch (Exception ex) {
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public void customize(Connector connector) {
        // TODO Auto-generated method stub
        this.connector = connector;
    }
}

@PreDestroy
public void shutdown() {
    logger.info("@PreDestroy shutdown");
    Schedulers.shutdown();
    Hystrix.reset();
    HystrixPlugins.reset();
}

}

如果在没有任何请求的情况下启动并关闭了应用程序,则它可以正常运行。

但是,如果有使用@HystrixCommand的请求,然后关闭应用程序,它将显示错误:

  

2019-07-18 10:49:40.094 WARN-[35-on(4)-127.0.0.1] [] oaclWebappClassLoaderBase:Web应用程序[ROOT]似乎已启动名为[DataPublisher]的线程,但未能阻止它。这很可能造成内存泄漏。线程的堆栈跟踪:   java.base / jdk.internal.misc.Unsafe.park(本机方法)   java.base / java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234)   java.base / java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2123)   java.base / java.util.concurrent.ScheduledThreadPoolExecutor $ DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182)   java.base / java.util.concurrent.ScheduledThreadPoolExecutor $ DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899)   java.base / java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1054)   java.base / java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1114)   java.base / java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:628)   java.base / java.lang.Thread.run(Thread.java:825)

     

2019-07-18 10:49:40.095 WARN-[35-on(4)-127.0.0.1] [] oaclWebappClassLoaderBase:Web应用程序[ROOT]似乎已启动名为[PollingServerListUpdater-0的线程] ],但未能阻止它。这很可能造成内存泄漏。线程的堆栈跟踪:   java.base / jdk.internal.misc.Unsafe.park(本机方法)   java.base / java.util.concurrent.locks.LockSupport.park(LockSupport.java:194)   java.base / java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject.await(AbstractQueuedSynchronizer.java:2081)   java.base / java.util.concurrent.ScheduledThreadPoolExecutor $ DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1177)   java.base / java.util.concurrent.ScheduledThreadPoolExecutor $ DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899)   java.base / java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1054)   java.base / java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1114)   java.base / java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:628)   java.base / java.lang.Thread.run(Thread.java:825)

似乎是因为Hystrix线程池未成功关闭,我试图使用Hystrix.reset()但没有运气。

您能告诉我如何避免此错误吗?

0 个答案:

没有答案