会话和事务的线程使用导致内存泄漏?

时间:2014-05-28 04:02:20

标签: java multithreading jsf tomcat memory-leaks

我正在寻找JSF应用程序中的内存泄漏。我已经阅读了各种文章,讨论在使用带有事务和会话的线程时可能发生的内存泄漏。以下代码是否会产生泄漏?此代码被调用数千次(对于页面请求)。

public class HibernateHelper 
{
      private static final ThreadLocal threadSession = new ThreadLocal();
      private static final ThreadLocal threadTransaction = new ThreadLocal();  

      public static Session startSessionWithDBName(SessionFactorySingleton.DBname dbname) 
      {
            Session s = getSessionWithDBName(dbname);
            beginTransaction(dbname);
            return s;
      }   

      @SuppressWarnings("unchecked")
      private static Session getSessionWithDBName(SessionFactorySingleton.DBname dbname) 
      {         
            Session s = (Session) threadSession.get();
            if (s == null) 
            {
                s = SessionFactorySingleton.getSessionFactory(dbname).openSession();                
                threadSession.set(s);
            }
            else 
            {
                String sf = ((SessionFactoryImpl)s.getSessionFactory()).getProperties().getProperty("hibernate.session_factory_name");
                if((dbname !=null && sf !=null) && !sf.equals(dbname.toString()))
                {                   
                    closeSessionBySessionFactoryName(sf);
                    s = SessionFactorySingleton.getSessionFactory(dbname).openSession();
                    threadSession.set(s);           
                }               
            }
            return s;
      }   

      @SuppressWarnings("unchecked")
      public static boolean isSessionOpen() 
      {         
            Session s = (Session) threadSession.get();
            if (s != null)              
                return s.isOpen();
            return false;           
      }   

      public static boolean wasTransactionCommited() 
      {         
            Transaction t = (Transaction) threadTransaction.get();          
            if (t != null) 
                return t.wasCommitted();
            return false;           
      } 

      @SuppressWarnings("unchecked")
      public static void closeSessionBySessionFactoryName(String sessionfactoryname) {          
            Session s = (Session) threadSession.get();          
            if (s != null && s.isOpen()) 
            {   
                String sfname = ((SessionFactoryImpl)s.getSessionFactory()).getProperties().getProperty("hibernate.session_factory_name");
                if(sfname.equals(sessionfactoryname))
                {               
                    try 
                    {
                        commitTransaction(sfname);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }                   
                    s.close();
                    threadSession.set(null);    
                }
            }           
        }

        /**
         * Start a new database transaction.
         */
        private static void beginTransaction(SessionFactorySingleton.DBname dbname) {           
            Session s = (Session) threadSession.get();                              
            if(s!=null)
            {
                log.info("Starting new transaction for this thread.");
                Transaction tx = s.beginTransaction();
                threadTransaction.set(tx);
            }                                           
        }

        /**
         * Commit the database transaction.
         */
        public static void commitTransaction(String sessionfactoryname) throws Exception {          
            Transaction tx = (Transaction) threadTransaction.get();
            try {
                if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
                    tx.commit();                    
                    log.info("Committed transaction for thread "+ Thread.currentThread().getName());                    
                }
                threadTransaction.set(null);
            } catch (Exception e) 
            {
                log.error("Exception when committing transaction: ", e);
                rollbackTransactionKeepingSessionOpen();
                throw e;
            }
        }

        /**
         * Rollback the database transaction.
         */
        public static void rollbackTransactionKeepingSessionOpen() {    
            Transaction tx = (Transaction) threadTransaction.get();
            threadTransaction.set(null);
            if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
                tx.rollback();
            }
        }

}

1 个答案:

答案 0 :(得分:1)

是的确如此 每个threadLocal实例都绑定到使用它的线程的生命周期 Tomcat的线程池很容易拥有数百个线程;每个线程都被重用并且永远不会被破坏 其中一些将被卡在I / O操作中,查询DB或诸如此类的东西,同时保持对开放Hibernate会话的引用(反过来可能包含许多附加实体)。
因此,在某些时期,应用程序可能会有许多无法通过GC回收的大对象图 我认为你应该以不同的方式管理Hibernate会话和事务。