L'application web semble avoir démarré un thread nommé [Timer-0] mais n'a pas réussi à l'arrêter.
j'utilise springboot 1.5.9.RELEASE+ Java 8+ tomcat 9 + Jersey+ Oracle et mon application a prévu méthode définie comme suit :
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
}
la classe d'emploi:
@Component
public class ClearCacheJob {
@Scheduled(fixedRate = 3600000, initialDelay = 10000)
public void clearErrorCodesCache() {
try {
logger.info("######## ClearCacheJob #########");
} catch (Exception e) {
logger.error("Exception in ClearCacheJob", e);
}
}
}
j'ai aussi une classe pour déréglementer le pilote oracle comme suit:
@WebListener
public class ContainerContextClosedHandler implements ServletContextListener {
private static final Logger logger = LoggerFactory.getLogger(ContainerContextClosedHandler.class);
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
logger.info("######### contextInitialized #########");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
logger.info("######### contextDestroyed #########");
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
logger.info(String.format("deregistering jdbc driver: %s", driver));
} catch (SQLException e) {
logger.info(String.format("Error deregistering driver %s", driver), e);
}
}
}
}
mais en arrêtant tomcat j'obtiens l'erreur suivante:
WARNING [Thread-11] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [hai]
appears to have started a thread named [Timer-0] but has failed to stop it.
This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Unknown Source)
java.util.TimerThread.mainLoop(Unknown Source)
java.util.TimerThread.run(Unknown Source)
veuillez indiquer pourquoi je suis arriver cette erreur et comment la corriger, merci.
4 réponses
Modifier ScheduleConfig
utiliser shutdownNow
au lieu de shutdown
comme méthode de destruction.
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod = "shutdownNow")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
}
je veux partager des solutions avec l'analyse des causes profondes de ce problème.
Pour Les Utilisateurs D'Oracle:
Solution#1:
Vous pouvez supprimer votre pilote Oracle de /WEB-INF/lib
le dossier et le mettre dans Tomcat's /lib
dossier. Ça pourrait résoudre votre problème.
Solution#2:
vous pouvez utiliser le vrai hack en dormant Le fil.
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
logger.info("######### contextDestroyed #########");
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
logger.info(String.format("deregistering jdbc driver: %s", driver));
} catch (SQLException e) {
logger.info(String.format("Error deregistering driver %s", driver), e);
}
}
try { Thread.sleep(2000L); } catch (Exception e) {} // Use this thread sleep
}
Ressources Lien:Solution de "Tomcat ne pouvez pas arrêter [Abandonné de nettoyage de la connexion fil]"
Solution#3:
Svetlin Zarev n'a rien dit d'inquiétant. C'est le message standard de tomcat. Il a fait une analyse des causes profondes comme ci-dessous:
Ce problème se produit lorsqu'une application a commencé Planifiéexécuteur (mais cela se produira avec tout autre Thread / TheadPool) et ne l'a pas fermé en bas sur contextDestroyed. Si vérifiez si vous fermez vos threads sur application / server arrêter.
Ressource Lien:Tomcat8 fuite de mémoire
Solution#4:
pour les utilisateurs D'Oracle, il y a de multiples réponses dans ce post: pour prévenir une fuite de mémoire, le pilote JDBC n'a pas été enregistré de force
Pour MySQL les utilisateurs,
Solution#5:
analyse des causes profondes avec Solution:
le fil conducteur du nettoyage des raccordements abandonnés dans les NonRegisteringDriver la classe a été remaniée pour avoir une méthode d'arrêt statique. La mémoire a été attribuée mais jamais libérée. Si vous rencontré ce problème de fuite, mettre en œuvre l'auditeur de contexte dans votre application avec le
AbandonedConnectionCleanupThread.shutdown()
appel dans lecontextDestroyed
méthode.ce problème a été trouvé dans les applications courant sous le Tomcat serveur d'application, mais il peut avoir aussi appliquée à d'autres les serveurs d'application.
Par exemple:
@WebListener public class YourThreadsListener implements ServletContextListener { public void contextDestroyed(ServletContextEvent arg0) { try { AbandonedConnectionCleanupThread.shutdown(); } catch (InterruptedException e) { } } ... }
notez que si le conteneur ne supporte pas les annotations, vous ajoutez description À web.xml:
<listener> <listener-class>user.package.YourThreadsListener</listener-class> </listener>
Ressource Lien: https://docs.oracle.com/cd/E17952_01/connector-j-relnotes-en/news-5-1-23.html
il est difficile de dire la cause racine mais le nom du thread [Timer-0] donne un indice pour le trouver. java.util.Timer
la classe crée des threads qui ont un motif de nom comme Timer-* comme vous pouvez le voir dans son code source.
public Timer() {
this("Timer-" + serialNumber());
}
Éventuellement les bibliothèques qui sont dans votre classpath commence par Timer thread mais ne l'annule pas ou le code qui fonctionne dans ce thread est bloqué.
je peut suggérer de mettre un point d'arrêt dans java.util.Timer
et le déboguer pour trouver tâches de travail. Il peut indiquer la cause profonde.
mes conclusions après avoir effectué quelques tests basés sur votre code et de la recherche en ligne:
il n'y a pas de quoi s'inquiéter (lien). Le processus Tomcat est terminé et il n'y a aucune fuite de mémoire.
Même si vous appelez quelque chose comme
AbandonedConnectionCleanupThread.shutdown()
, vous pouvez toujours obtenir le même Avertissement (lien)Cet avertissement se produit lors de l'appel de
startup.sh
etshutdown.sh
. En exécutant Tomcat à partir D'Eclipse, il ne montre pas cet avertissement.Votre méthode d'arrêt pour l'
Executor
est probablement appelé. Pour mes tests, il était appelé même si je n'avais pas défini ledestroyMethod
pour l'exécuteur testamentaire.dans ce cas, la présente mise en garde n'est pas liée à une fève D'ordonnancement de printemps.
Executors.newScheduledThreadPool
retourne un nouveauScheduledThreadPoolExecutor
, qui a la méthode destroy et il est détruit, comme je l'ai souligné plus tôt. Vous pouvez débogage et de voir par vous-même.Cependant, il y a quelque part dans votre code appelant
new java.util.Timer
, qui appellenew TimerThread()
, ass vu de votre logging, et comme souligné par @Claudio Corsi.
pour le débogage et si vous utilisez Eclipse, vous devez joindre le code source de votre version JDK. Ouvrir la déclaration de classe (tenir ctrl et choisir la déclaration ouverte) et cliquez sur le bouton" Joindre le Code Source". Assurer vous avez téléchargé l' exactement la même version. Tu n'as même pas besoin d'extraire la fermeture éclair. Si vous utilisez Maven, il suffit de tenir sur un peu qu'il va TÉLÉCHARGER pour lui-même.
alors, placez un point de rupture dans le constructeur pour java.util.Timer
et commencez à déboguer votre application.
Modifier: après avoir identifié une référence à java.util.Timer
, de l'enregistrer (comme un haricot, si c'est pas un) et fait appel à son cancel
méthode de destruction de contexte.