Fuite de mémoire sur Tomcat 7 avec Oracle JDBC drivers 12c - oracle.jdbc.conducteur fil a omis de s'arrêter
J'ai une application web déployée dans Tomcat 7.0.54 qui utilise une source de données pour se connecter à une base de données Oracle 11g. La source de données est configuré dans META-INF/context.xml
et je l'ai placé ojdbc7.jar dans <tomcat-install-dir>/lib
. J'utilise une recherche JNDI pour récupérer la source de données à laquelle je stocke dans un singleton, de sorte que chaque classe DAO peut l'utiliser.
Tout fonctionne comme prévu, mais quand je annuler le déploiement de l'application (via Tomcat manager app) je vois dans les logs:
Oct 03, 2014 3:06:55 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/myapp] appears to have started a thread named [oracle.jdbc.driver.BlockSource.ThreadedCachingBlockSource.BlockReleaser] but has failed to stop it. This is very likely to create a memory leak.
Oct 03, 2014 3:06:57 PM org.apache.catalina.startup.HostConfig undeploy
INFO: Undeploying context [/myapp]
Quand je debug je peux voir ce thread est créé dès que la base de données est accessible (via la source de données).
Ma source de données config:
<Context antiResourceLocking="false">
<Resource name="jdbc/myapp" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
maxActive="20" maxIdle="10" maxWait="-1"
username="myuser" password="mypass"
url="jdbc:oracle:thin:@myserver:1521:mysid"
removeAbandoned="true" removeAbandonedTimeout="10" logAbandoned="true"
validationQuery="SELECT 1 FROM DUAL"
testOnBorrow="true" testOnReturn="true" testWhileIdle="true"
timeBetweenEvictionRunsMillis="1800000" numTestsPerEvictionRun="3"
minEvictableIdleTimeMillis="1800000"
/>
</Context>
MODIFIER
Une enquête plus poussée a révélé que le problème se produit si oui ou non la source de données est accessible lors de l'application (ou servlet) initialisation.
En réalité, le problème de thread est créé, et donc le problème n'existe, lors de l'utilisation de la 12c versions de Oracle JDBC drivers (soit ojdbc6.jar ou ojdbc7.jar).
Si je reviens à l'aide de la version de 11.2.0.4 ojdbc6.jar le fil n'est jamais créé et la fuite de mémoire avertissement n'apparaît jamais.
Dois-je downgrade pilote JDBC (comme suggéré dans https://stackoverflow.com/a/9177263/4105953)?
WEB-INF/lib
répertoire. Car ce serait de l'auto de s'inscrire et de commencer certains de l'Oracle JDBC choses. Voir aussi here.merci, mais j'ai d'ores et déjà assuré que le pilote JDBC est seulement dans
tomcat/lib
et non pas de l'application WEB-INF/lib
OriginalL'auteur finchie | 2014-10-03
Vous devez vous connecter pour publier un commentaire.
J'ai trouvé une longue discussion sur le sujet ici. La conclusion est qu'il crée un "taille fixe fuite de mémoire", c'est à dire ultérieure redéploie n'augmentera pas la fuite de mémoire.
Je n'ai pas de Support d'Oracle access, mais le bug ID mentionné dans la discussion est 16841748 (Mai 2013, pourrait être résolu maintenant).
Une solution possible est d'utiliser la source de données une fois (get connexion, de faire mannequin de requête, à proximité de connexion) quand Tomcat est lancé via un custom servlet qui est configuré pour "load-on-startup" dans
tomcat/conf/web.xml
. Cela devrait démarrer le pilote Oracle thread(s) (voir aussi le FAQ à propos du pilote threads) à l'extérieur de la portée de la classe loader de votre application web, empêchant ainsi la "taille fixe fuite de mémoire".Noter qu'un problème similaire existe pour le pilote JDBC MySQL mais a un solution décente. Une telle solution peut exister pour une version récente de l'Oracle JDBC driver (je ne sais pas).
Hmm, regardé dans le code décompilé et a constaté que chaque oracle.jdbc.le pilote.PhysicalConnection crée un "BlockSource" thread. Cela explique pourquoi "load-on-startup" ne fonctionne pas (j'ai supposé que c'était un général thread lancé par le pilote, pas par connexion). À l'aide de l'ancienne version du pilote, comme vous l'avez décrit dans la mise à jour de votre question, apparaît comme une meilleure solution.
Je pense que la discussion est en fait un semblable, mais sans rapport avec question, c'est pourquoi la solution de contournement n'a eu aucun effet. Il y a un Oracle doc ID pour cela, cependant, et un patch disponible: JDBC Mince Pilote Fuites Threads Avec Tomcat (Doc ID 1901449.1)
Ce n'est pas une "taille fixe" de fuite. Il crée des chargeur de classe fuites qui sera tôt ou tard finir dans un dépassement de mémoire d'erreur. Quand vous regardez le tas de vidage, vous pouvez voir clairement que tous les arrêtés d'application web classe chargeurs ne pouvait pas être nettoyés de leur chargeur de classe est encore référencée par
oracle.jdbc.driver.BlockSource$ThreadedCachingBlockSource$BlockReleaser.contextClassLoader
OriginalL'auteur vanOekel
C'est normal, cela arrive quand vous déploiement à chaud dans Tomcat. Il ne sera pas vous poser de problèmes normalement dans la production parce que vous n'avez généralement pas de maintenir au chaud le déploiement de mises à jour en production, vous venez de vous arrêter et de redémarrer le serveur à la place.
OriginalL'auteur Triton Man
Ce problème ne se produit pas seulement avec Oracle JDBC driver (oracle.jdbc.le pilote.BlockSource.ThreadedCachingBlockSource.BlockReleaser).
Si tout de la 3ème partie commence un fil de démon pour l'exécution de certaines tâches, tandis que l'arrêt de Tomcat journaux message d'Avertissement pour eux aussi.
Aussi, ce problème existe avec Tomcat 8.5.X versions.
Solution:
Ce que j'ai trouvé la solution pour obtenir le Groupe de Thread pour le thread en cours et de les interrompre. Il sera assurez-vous que avant d'arrêter le Tomcat de tous les fils de démon sont tués.
code ci-dessous doit être ajouté à la "contextDestroyed" méthode
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
threadGroup.interrupt();
OriginalL'auteur subrat patra