ABOUT ME

B급 개발자 이야기, 인생은 B 컷이 전부다.

Today
Yesterday
Total
  • Tomcat에서 DBCP 사용할 때 Memory leak
    개발 2014. 5. 9. 12:40

    Problem Domain


    registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. 


     - dbcp, boneCP를 사용하던... 에러는 발생한다.


     - mySQL, Oracle 관계 없이 에러는 발생한다.


     - JPA(+ Hibernate)를 사용할 때만 에러가 발생한다. (JPA를 사용하지 않을 때는 에러가 발생하지 않는다.)

        : org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean 및 관련 클래스를 등록하여

          사용할 경우 (나만그런가?)



    Solve


    해결 방법... google.com과 stackoverflow.com에서 방황을...-_-;;


    1. DataSource가 Close 되는 시점에 명시적으로 드라이버를 unregister 시켜준다.


    - extended BasicDataSource class

    public class DisposableBasicDataSource extends BasicDataSource { 

    @Override

    public synchronized void close() throws SQLException {

    DriverManager.deregisterDriver(DriverManager.getDriver(url));

    super.close();

    }

    }


    - added listener

    public class JdbcDriverRegistrationListener implements ServletContextListener {

        /**

         * Default constructor. 

         */

        public JdbcDriverRegistrationListener() {

            // TODO Auto-generated constructor stub

        }


    /**

         * @see ServletContextListener#contextDestroyed(ServletContextEvent)

         */

        public void contextDestroyed(ServletContextEvent sce)  {

        /**

        * simple

        */

        /*

        Enumeration<Driver> drivers = DriverManager.getDrivers();

            while (drivers.hasMoreElements()) {

                Driver driver = drivers.nextElement();

                try {

                    DriverManager.deregisterDriver(driver);

                    log.info(String.format("deregistering jdbc driver: %s", driver));

                } catch (SQLException e) {

                log.info(String.format("Error deregistering driver %s", driver), e);

                }

            }

            */

            // ... First close any background tasks which may be using the DB ...

            // ... Then close any DB connection pools ...


            // Now deregister JDBC drivers in this context's ClassLoader:

            // Get the webapp's ClassLoader

            ClassLoader cl = Thread.currentThread().getContextClassLoader();

            // Loop through all drivers

            Enumeration<Driver> drivers = DriverManager.getDrivers();

            while (drivers.hasMoreElements()) {

                Driver driver = drivers.nextElement();

                if (driver.getClass().getClassLoader() == cl) {

                    // This driver was registered by the webapp's ClassLoader, so deregister it:

                    try {

                        log.info("Deregistering JDBC driver {}", driver);

                        DriverManager.deregisterDriver(driver);

                    } catch (SQLException ex) {

                        log.error("Error deregistering JDBC driver {}", driver, ex);

                    }

                } else {

                    // driver was not registered by the webapp's ClassLoader and may be in use elsewhere

                    log.trace("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader", driver);

                }

            }

        } 

        /**

         * @see ServletContextListener#contextInitialized(ServletContextEvent)

         */

        public void contextInitialized(ServletContextEvent sce)  { 

             // TODO Auto-generated method stub

        }

    }




    2. 톰켓 lib 폴더에 jdbc 드라이버 jar를 복사한다.


    3. JNDI를 사용한다.



    컨테이너 리로드가 필요없는 서버는 상관없음.


    톰켓에서만 나는건지 아니면 다른 WAS도 그런건지 잘 모르겠음.

    '개발' 카테고리의 다른 글

    문자열 한줄씩 읽기  (0) 2014.08.29
    Maven Repository 사이트  (0) 2014.08.27
    푸시에 대한 기본 개념 - 외부 링크  (0) 2014.04.21
    [flex/actionscript] as3 프레임워크  (0) 2014.04.09
    [외부] Flex 기반 Vector Drawing Editor  (0) 2014.04.08
Designed by Tistory.