首页 文章

独立的jdbc-pool实现内存泄漏

提问于
浏览
2

我试图在独立的Web应用程序中实现jdbc-pool(自包含 - 不依赖于server.xml),以便可以将其移动到可能早于7.0的tomcat安装 .

我使用sourceforge驱动程序连接到MSSQL Server(net.sourceforge.jtds.jdbc.Driver)

一切都运行良好,除了这个错误:

严重:Web应用程序[/ jdbc-pool]似乎已经启动了一个名为[[Pool-Cleaner]:Tomcat Connection Pool [1-12524859]]但未能阻止它的线程 . 这很可能造成内存泄漏 .

基于this我确定我需要关闭jdbc-pool数据源 . 我在该帖子的最后一行遇到了麻烦:

如果在应用程序上下文中配置它,那么这只是意味着您在Web应用程序停止时忘记在连接池上调用DataSource.close . >这是令人困惑的建议,因为javax.sql.DataSource没有close()方法 . 为了调用close,必须将其强制转换为您正在使用的数据源 .

我如何找出我正在使用的数据源类型以及它的类在哪里?我能以某种方式从驱动程序 jar 中提取它吗?

除了使用池的servlet之外,我使用ServletContextListener,以便我可以立即从contextInitialized方法开始使用池连接 . 我开始添加代码以在此ServletContextListener的contextDestroyed方法中终止连接,但挂起问号所在的位置:

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.sql.DataSource;

public class JdbcPoolListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent myServletContextEvent) {

        // initialize jdbc-pool datasource to start out with pooled connections 
        try {
            Context myContext = (Context) new InitialContext().lookup("java:comp/env");
            DataSource myDataSource = (DataSource) myContext.lookup("jdbc/db");
            myServletContextEvent.getServletContext().setAttribute("JdbcPool", myDataSource);
        } catch (NamingException e) {
            System.out.println("Error initializing jdbc-pool datasource");
            e.printStackTrace();
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent myServletContextEvent) {

        // failed attempt to close the data source
        ServletContext myServletContext = myServletContextEvent.getServletContext();
        //DataSource myDataSource = (DataSource) myServletContext.getAttribute("JdbcPool");
        DataSource dataSource = (DataSource)((???) myServletContext.getAttribute(contextAttribute)).getConfiguration().getEnvironment().getDataSource();
        dataSource.close();
        myServletContext.removeAttribute("JdbcPool");

        // deregister JDBC driver to prevent Tomcat 7 from complaining about memory leaks
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                System.out.println(String.format("Deregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                System.out.println(String.format("Error deregistering driver %s", driver));
                e.printStackTrace();
            }
        }
    }
}

1 回答

  • 2

    解决了这一点,我注意到 tomcat.jdbc.pool.DataSourceProxy 有一个close方法,所以我将数据源转换为 DataSourceProxy ,然后在其上调用closed . 我现在不再在日志中获得tomcat内存泄漏错误 .

    SOLUTION:

    import java.sql.Driver;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Enumeration;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.sql.DataSource;
    
    import org.apache.tomcat.jdbc.pool.DataSourceProxy;
    
    public class JdbcPoolListener implements ServletContextListener {
    
        @Override
        public void contextInitialized(ServletContextEvent myServletContextEvent) {
    
            // initialize jdbc-pool datasource to start out with pooled connections 
            try {
                Context myContext = (Context) new InitialContext().lookup("java:comp/env");
                DataSource myDataSource = (DataSource) myContext.lookup("jdbc/cf");
                myServletContextEvent.getServletContext().setAttribute("JdbcPool", myDataSource);
            } catch (NamingException e) {
                System.out.println("Error initializing jdbc-pool datasource");
                e.printStackTrace();
            }
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent myServletContextEvent) {
    
        // close datasource from proxy?
        ServletContext myServletContext = myServletContextEvent.getServletContext();
            DataSourceProxy myDataSource = (DataSourceProxy) myServletContext.getAttribute("JdbcPool");
            myDataSource.close();       
            myServletContext.removeAttribute("JdbcPool");
    
            // deregister JDBC driver to prevent Tomcat 7 from complaining about memory leaks
            Enumeration<Driver> drivers = DriverManager.getDrivers();
            while (drivers.hasMoreElements()) {
                Driver driver = drivers.nextElement();
                try {
                    DriverManager.deregisterDriver(driver);
                    System.out.println(String.format("Deregistering jdbc driver: %s", driver));
                } catch (SQLException e) {
                    System.out.println(String.format("Error deregistering driver %s", driver));
                    e.printStackTrace();
                }
            }
        }
    }
    

相关问题