java - How to get rid of tomcat memory leak log entries caused by a sleeping thread -
any idea how can rid of following tomcat log entries:
severe: web application [/my-app] appears have started thread named [thread-11] has failed stop it. create memory leak. jun 29, 2015 11:14:33 org.apache.catalina.loader.webappclassloader clearreferencesthreads
i'm getting them while shutting down tomcat 7.0.42.
the thread dump looks this:
"thread-11" daemon prio=10 tid=0x00007fedc0bd5000 nid=0x2983 waiting on condition [0x00007fedbacef000] java.lang.thread.state: timed_waiting (sleeping) @ java.lang.thread.sleep(native method) @ com.my.app.test$workerthread.run(test.java:248)
where java line 248 is: sleep(1000*60*pollintervalminutes);
public void start() { workerthread t= new workerthread(this); t.setdaemon(true); t.start(); } private class workerthread extends thread { controller controller=null; int pollintervalminutes=0; private boolean alive = true; public workerthread(controller controller) { this.controller=controller; pollintervalminutes=60; } @override public void run() { while(alive) { try { sleep(1000*60*pollintervalminutes); controller.createallprojectsifneeded(); } catch (exception e) { alive = false; } } } }
thanks
problem seems tomcat doesn't try , stop non-managed threads created application.
looking implementation of org.apache.catalina.loader.webappclassloader clearreferencesthreads
reports error, jvm threads skipped cleanup procedure.
due this, interruptedexception never thrown , therefore alive not set false, perhaps expected.
@suppresswarnings("deprecation") private void clearreferencesthreads() { thread[] threads = getthreads(); // iterate on set of threads (thread thread : threads) { if (thread != null) { classloader ccl = thread.getcontextclassloader(); if (ccl == this) { // don't warn thread if (thread == thread.currentthread()) { continue; } // jvm controlled threads threadgroup tg = thread.getthreadgroup(); if (tg != null && jvm_thread_group_names.contains(tg.getname())) { // httpclient keep-alive threads if (clearreferenceshttpclientkeepalivethread && thread.getname().equals("keep-alive-timer")) { thread.setcontextclassloader(parent); log.debug(sm.getstring( "webappclassloader.checkthreadshttpclient")); } // don't warn remaining jvm controlled threads continue; } // skip threads have died if (!thread.isalive()) { continue; } // timerthread can stopped safely treat separately if (thread.getclass().getname().equals( "java.util.timerthread") && clearreferencesstoptimerthreads) { clearreferencesstoptimerthread(thread); continue; } if (isrequestthread(thread)) { log.error(sm.getstring("webappclassloader.warnrequestthread", contextname, thread.getname())); } else { log.error(sm.getstring("webappclassloader.warnthread", contextname, thread.getname())); } // don't try stop threads unless explicitly // configured if (!clearreferencesstopthreads) { continue; } // if thread has been started via executor, try // shutting down executor try { field targetfield = thread.getclass().getdeclaredfield("target"); targetfield.setaccessible(true); object target = targetfield.get(thread); if (target != null && target.getclass().getcanonicalname().equals( "java.util.concurrent.threadpoolexecutor.worker")) { field executorfield = target.getclass().getdeclaredfield("this$0"); executorfield.setaccessible(true); object executor = executorfield.get(target); if (executor instanceof threadpoolexecutor) { ((threadpoolexecutor) executor).shutdownnow(); } } } catch (securityexception e) { log.warn(sm.getstring( "webappclassloader.stopthreadfail", thread.getname(), contextname), e); } catch (nosuchfieldexception e) { log.warn(sm.getstring( "webappclassloader.stopthreadfail", thread.getname(), contextname), e); } catch (illegalargumentexception e) { log.warn(sm.getstring( "webappclassloader.stopthreadfail", thread.getname(), contextname), e); } catch (illegalaccessexception e) { log.warn(sm.getstring( "webappclassloader.stopthreadfail", thread.getname(), contextname), e); } // method deprecated , reason. // risky code option @ point. // *very* reason apps clean-up // themselves. thread.stop(); } } } }
there 3 options can think of how avoid memory leak:
- provide shutdown hook thread knows spawned threads , can interrupt them
- do not spawn threads spin endlessly in while loop can stop when finished processing
wrap threads in
executorservice
, callshutdownnow()
upon application shutdown event.this can achieved service class annotated
@weblistener
, callingshutdownnow()
in method:contextdestroyed(servletcontextevent event)
.
shutdownnow()
attempts stop actively executing tasks, halts processing of waiting tasks, , returns list of tasks awaiting execution. method not wait actively executing tasks terminate. use
awaittermination
that.there no guarantees beyond best-effort attempts stop processing actively executing tasks. example, typical implementations cancel via
thread.interrupt()
, task fails respond interrupts may never terminate.
Comments
Post a Comment