spring-cloud-netflix icon indicating copy to clipboard operation
spring-cloud-netflix copied to clipboard

Memory leak while deploying spring-cloud-netflix application on standalone tomcat

Open ghost opened this issue 8 years ago • 25 comments

Tomcat fail to stop thread named ServoMonitorGetValueLimiter. A thread called ServoMonitorGetValueLimiter started by the the application which is never stopped. This thread is started by MonitorRegistryMetricPoller of com.netflix.servo . In fact service is failed to stop the thread. The object of this class is a component in ServoMetricCollector of org.springframework.cloud.netflix.servo to exposes servo metrics to the metric endpoint.

when application is undeployed it is unable to unregister the MBean also (com.netflix.servo)

ghost avatar Aug 18 '15 22:08 ghost

Sorry for the delay in responding. Is this still an issue? Is it a memory leak, or just the thread isn't shut down properly?

spencergibb avatar Nov 11 '15 05:11 spencergibb

I am facing similar issue. While undeploying application from tomcat it is failed to stop thread named ServoMonitorGetValueLimiter causing memory leak. After undeploying the application multiple times, a number of ServoMonitorGetValueLimiter instances remains alive in perm area which is causing java.lang.OutOfMemory exception. I am using Angel.SR4 version of spring-cloud-starter-parent.

AnilK11 avatar Nov 26 '15 05:11 AnilK11

Is it a tomcat only problem? What about undertow?

cforce avatar Nov 26 '15 12:11 cforce

What version of Tomcat is that?

dsyer avatar Nov 26 '15 15:11 dsyer

I am using tomcat 8.0.

AnilK11 avatar Nov 30 '15 06:11 AnilK11

There's an option in Tomcat to forcibly stop threads and clean up class loaders. I thought it was on by default, but maybe not (or maybe you switched it off). Does that help?

dsyer avatar Nov 30 '15 07:11 dsyer

This is happening in the netflix servo code spinning raw Thread MonitorRegistryMetricPoller.java 77e6036

sprgn avatar Jan 19 '16 19:01 sprgn

Following context attributes take care of most of the loose threads out there except for ServoMonitorGetValueLimiter.

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context clearReferencesStopTimerThreads="true" clearReferencesStopThreads="true">
</Context>

sprgn avatar Jan 19 '16 19:01 sprgn

@sprgn Are you using atlas or specatator? I don't see MonitorRegistryMetricPoller get instantiated.

spencergibb avatar Jan 19 '16 20:01 spencergibb

No, neither one. Going off the name of the thread in the stack trace, and MonitorRegistryMetricPoller is the only one that creates threads with name ServoMonitorGetValueLimiter-%d

19-Jan-2016 14:15:22.673 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ws_eureka] appear
s to have started a thread named [ServoMonitorGetValueLimiter-0] 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.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 java.lang.Thread.run(Thread.java:745)

sprgn avatar Jan 19 '16 20:01 sprgn

Well, I should say I'm not using either one that I know of, at least not explicitly.

sprgn avatar Jan 19 '16 20:01 sprgn

@sprgn MonitorRegistryMetricPoller doesn't get instantiated in a basic sample. Do you have a sample app that shows the problem?

spencergibb avatar Jan 19 '16 20:01 spencergibb

@spencergibb here it is link to ws_eureka app codebase

sprgn avatar Jan 19 '16 20:01 sprgn

It expects tomcat to be running on port 80.

sprgn avatar Jan 19 '16 20:01 sprgn

Ah, I am running Brixton, you are running Angel.

spencergibb avatar Jan 19 '16 21:01 spencergibb

Running Brixton.M4 it gives similar error, but for a different named thread now

19-Jan-2016 15:17:12.879 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ws_eureka] appear
s to have started a thread named [spring.cloud.inetutils] 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.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 java.lang.Thread.run(Thread.java:745)

sprgn avatar Jan 19 '16 21:01 sprgn

That makes sense!

spencergibb avatar Jan 19 '16 21:01 spencergibb

How can I cancel that thread?

sprgn avatar Jan 19 '16 21:01 sprgn

You'd likely need to use reflection in M4. This commit should fix it.

spencergibb avatar Jan 19 '16 21:01 spencergibb

Thanks! Reflection worked to fix it for now until the fix is released. Worked via a ServletContextListener contextDestroyed method

import ch.qos.logback.classic.LoggerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.util.InetUtils;
import org.springframework.stereotype.Component;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;

@WebListener
@Component
public class LogbackShutdownListener implements ServletContextListener {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public void contextDestroyed(ServletContextEvent sce) {
        Field field = null;
        try {
            field = InetUtils.class.getDeclaredField("executor");

            field.setAccessible(true);
            Object es = field.get(null);
            ((ExecutorService)es).shutdownNow();
        } catch (Exception e) {
            //
        }

        LoggerContext context = (LoggerContext)LoggerFactory.getILoggerFactory();
        this.logger.warn("Shutting down loggerContext in contextDestroyed");
        context.stop();
    }

    public void contextInitialized(ServletContextEvent sce) {
    }
}

sprgn avatar Jan 19 '16 23:01 sprgn

Is Angel.SR4 not recommended to be used then at this point?

sprgn avatar Jan 20 '16 15:01 sprgn

Angel does not have that thread pool in it (the one referenced by Spencer as fixed in master). Are we talking at cross purposes here?

dsyer avatar Jan 20 '16 16:01 dsyer

Angel has different threads that remain open. @sprgn Angel.SR4 is the GA release we support.

spencergibb avatar Jan 20 '16 17:01 spencergibb

@sprgn Any update on this issue ? We are getting the same error in Greenwich.M3 cloud version as well. By using shutdown hook that you mentioned before, we are able to fix the error. Wondering, if any of the future spring-cloud release will fix this.

jsaraiy avatar Dec 06 '18 23:12 jsaraiy

It’s probably not possible for your current issue to be the same as this one (the code changed a lot since Angel). Please open a new issue and provide detailed steps to reproduce.

dsyer avatar Dec 07 '18 07:12 dsyer