2017-06-30 5 views
0
@Configuration 
public class DataSourceConfiguration 
{ 

    @Autowired 
    private Environment env; 

    @Bean(destroyMethod = "close") 
    public ComboPooledDataSource dataSource() 
    { 

     String datasourcePathStartsWith = "datasource."; 

     ComboPooledDataSource dataSource = new ComboPooledDataSource(); 
     try 
     { 
      dataSource.setContextClassLoaderSource("library"); 
      dataSource.setPrivilegeSpawnedThreads(true); 
      dataSource.setDriverClass("oracle.jdbc.driver.OracleDriver"); 
      dataSource.setJdbcUrl(env.getProperty(datasourcePathStartsWith + "url")); 
      dataSource.setUser(env.getProperty(datasourcePathStartsWith + "user")); 
      dataSource.setPassword(env.getProperty(datasourcePathStartsWith + "password")); 
      dataSource.setMinPoolSize(Integer.parseInt(env.getProperty(datasourcePathStartsWith + "minPoolSize"))); 
      dataSource.setMaxPoolSize(Integer.parseInt(env.getProperty(datasourcePathStartsWith + "maxPoolSize"))); 
      dataSource.setCheckoutTimeout(Integer.parseInt(env.getProperty(datasourcePathStartsWith + "checkoutTimeout"))); 
      dataSource.setMaxIdleTime(Integer.parseInt(env.getProperty(datasourcePathStartsWith + "maxIdleTime"))); 
      dataSource.setMaxStatements(Integer.parseInt(env.getProperty(datasourcePathStartsWith + "maxStatements"))); 
     } 
     catch (PropertyVetoException e) 
     { 
      e.printStackTrace(); 
     } 
     return dataSource; 
    } 


} 

Voici mon code. Cela fonctionne "bien" sur Tomcat 7 - quand je redéploie plusieurs fois l'application et que j'utilise la fonction "Trouver des fuites", cela ne montre rien. Mais si j'ajoute sessionFactory, les problèmes apparaissent tous les redéployer:Problème de Permgen lors de l'utilisation de LocalSessionFactoryBean de Spring

Les applications Web suivantes ont été arrêtées (rechargées, non déployé), mais leurs classes de courses précédentes sont toujours chargées en mémoire, ce qui provoque une fuite de mémoire (utilisez un profileur pour confirmer):    /testPermGen
   /testPermGen
   /testPermGen

@Bean 
    public LocalSessionFactoryBean sessionFactory(DataSource dataSource) 
    { 
     LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean(); 
     sessionFactoryBean.setDataSource(dataSource); 
     return sessionFactoryBean; 
    } 

J'ai essayé ce code, sans câblage à dataSource, sans succès. On dirait que le problème est avec LocalSessionFactoryBean non fermé à l'arrêt de l'application.

@Bean(destroyMethod = "destroy") 
    public LocalSessionFactoryBean sessionFactory() 
    { 
     LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean(); 
     return sessionFactoryBean; 
    } 

Tomcat est en cours d'exécution avec des drapeaux suivants:

-XX:MaxPermSize=128m 
-XX:+UseConcMarkSweepGC 
-XX:+CMSClassUnloadingEnabled 
-XX:+CMSPermGenSweepingEnabled 

Il est possible de résoudre ce problème avec les fuites de mémoire?

MISE À JOUR:

J'ai téléchargé l'ensemble du projet (4 fichiers) sur GitHub pour reproduire la fuite de mémoire: https://github.com/anton-09/TestPermGen

classloader fuite de prévention de

Mattias Jiderhamn n'a pas aidé beaucoup, je avez obtenu ce journal dans Tomcat 7:

июл 03, 2017 11:44:27 AM se.jiderhamn.classloader.leak.prevention.JULLogger warn 
WARNING: Waiting for Thread 'Thread[Resource Destroyer in BasicResourcePool.close(),5,main]' of type com.mchange.v2.resourcepool.BasicResourcePool$5 loaded by protected ClassLoader with contextClassLoader = protected ClassLoader or child for 5000 ms. Thread stack trace: 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(SocketInputStream.java:152) 
    at java.net.SocketInputStream.read(SocketInputStream.java:122) 
    at oracle.net.ns.Packet.receive(Packet.java:300) 
    at oracle.net.ns.DataPacket.receive(DataPacket.java:106) 
    at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315) 
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:260) 
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:185) 
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:102) 
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124) 
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80) 
    at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137) 
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290) 
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192) 
    at oracle.jdbc.driver.T4C7Ocommoncall.doOLOGOFF(T4C7Ocommoncall.java:61) 
    at oracle.jdbc.driver.T4CConnection.logoff(T4CConnection.java:543) 
    at oracle.jdbc.driver.PhysicalConnection.close(PhysicalConnection.java:3984) 
    at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:642) 
    at com.mchange.v2.c3p0.impl.NewPooledConnection.closeMaybeCheckedOut(NewPooledConnection.java:255) 
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:622) 
    at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:1076) 
    at com.mchange.v2.resourcepool.BasicResourcePool.destroyResource(BasicResourcePool.java:1101) 
    at com.mchange.v2.resourcepool.BasicResourcePool.destroyResource(BasicResourcePool.java:1062) 
    at com.mchange.v2.resourcepool.BasicResourcePool.access$100(BasicResourcePool.java:44) 
    at com.mchange.v2.resourcepool.BasicResourcePool$5.run(BasicResourcePool.java:1316) 
июл 03, 2017 11:44:27 AM se.jiderhamn.classloader.leak.prevention.JULLogger info 
INFO: Thread 'Thread[Resource Destroyer in BasicResourcePool.close(),5,main]' of type com.mchange.v2.resourcepool.BasicResourcePool$5 loaded by protected ClassLoader with contextClassLoader = protected ClassLoader or child no longer alive - no action needed. 

On dirait everithing ok, mais « trouver les fuites » Tomcat de reportages sur les nouvelles fuites de mémoire.

SOLUTION

Le problème est avec la journalisation JBoss inclus dans la dépendance Hibernate. J'ai exclu la dépendance jboss-logging de hibernate-core, copié jboss-logging-3.3.0.Final.jar dans le dossier "lib" de Tomcat et le problème est parti.

<dependency> 
    <groupId>org.hibernate</groupId> 
    <artifactId>hibernate-core</artifactId> 
    <version>${hibernate.version}</version> 
    <exclusions> 
     <exclusion> 
      <groupId>org.jboss.logging</groupId> 
      <artifactId>jboss-logging</artifactId> 
     </exclusion> 
     <exclusion> 
      <groupId>org.jboss.logging</groupId> 
      <artifactId>jboss-logging-annotations</artifactId> 
     </exclusion> 
    </exclusions> 
</dependency> 
+0

Essayez une autre connexion mise en œuvre de la piscine? Spring Boot par exemple prend en charge (dans l'ordre de préférence): Tomcat, HikariCP, DBCP (obsolète), DBCP2 – Strelok

Répondre

1

Il existe many third party libraries qui peuvent provoquer des fuites de ClassLoader. Si vous voulez traquer le délinquant dans votre cas (ce qui pourrait être à la fois amusant et éducatif!), Je recommande de suivre les instructions au this blog post of mine. Pour se débarrasser du problème, il suffit d'ajouter my ClassLoader Leak Prevention library à votre demande. Le contrevenant est parfois également révélé simplement en regardant les journaux après avoir ajouté cette bibliothèque.

+0

Je connais le délinquant - c'est la bibliothèque C3P0. Votre classloader n'a pas aidé, j'ai mis à jour ma question avec les logs Tomcat – AHTOH

+0

Quand vous dites que cela n'a pas aidé, qu'est-ce que cela signifie? Le serveur finit par tomber en panne avec OutOfMemoryError? Tomcat se connecte encore "... mais leurs classes des précédentes sont encore chargées en mémoire ..."? Le problème ne peut pas être C3PO lui-même mais le pilote Oracle, qui a été connu pour provoquer des fuites. Est-il possible pour vous d'essayer une autre base de données? –

+0

Tomcat rapports sur les classes, encore chargé en mémoire.Après un certain nombre d'opérations d'arrêt/démarrage, j'ai reçu l'erreur PermGen OutOfMemory. J'avais tort à propos de C3P0 (peut-être). Je viens d'essayer une autre base de données (mysql) et une autre bibliothèque de pool de connexions (hikari) avec le même résultat! La seule façon de résoudre ce problème est de commenter pleinement le bean sessionFactory !! Peut-être que c'est la faute de Spring? – AHTOH