Java - Tomcat GC 不会释放。总是导致崩溃,找不到任何内存泄漏

标签 java tomcat garbage-collection jvm out-of-memory

我的 tomcat 应用程序几乎没有问题。 我正在使用具有 1024M 内存的 linux 服务器。 我在 tomcat 上部署了我的应用程序,一切正常。 最近我注意到“Tenured Gen”堆内存在应该释放的时候没有释放...... 它达到 99% 然后崩溃 tomcat.. 我用 VisualVM 检查我的应用程序,结果相同。 它填满了内存,而“老一代”永远不会释放。

这是应用程序在没有请求的情况下运行几分钟的情况:

IMG:Everything looks normal

当我开始循环发送带有 200 个线程的请求时 这是发生了什么:

IMG:all memories are full

然后我在 MAT 上检查数据,这是我的结果:

IMG:look like a memory leak

IMG:Problem with the sql jdbc?

IMG:Can't understand what is wrong

这是我的 ConnectionPool 类:

public class ConnectionPool {

    private static ConnectionPool singleton = null; 

    private ArrayList<Connection> freeConnections; 
    private ArrayList<Connection> allConnections; 
    private int MAX_CONNECTIONS = 1;

    private final String shema = "Topic";

    private final String url = "jdbc:mysql://localhost:3306/"+shema+"?  autoReconnect=true&useSSL=false";
    private final String username = "root";
    private final String password = "password";




    public static ConnectionPool getInstance(){
        if (singleton == null)
        {
            synchronized (ConnectionPool.class) {
                if (singleton == null){
                    System.out.println("ConnectionPool get instance");
                    try {
                        singleton = new ConnectionPool();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } //this will invoke the constructor
                }
            }
        }
        return singleton;
    }

    private ConnectionPool() throws Exception {

        freeConnections = new ArrayList<Connection>();
        allConnections = new ArrayList<Connection>();
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        for (int i = 0; i < MAX_CONNECTIONS; i++) {
            try {
                addNewConnection();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }
    private void addNewConnection() throws SQLException {
        try {

            Connection conn = DriverManager.getConnection(url, username,  password);
            freeConnections.add(conn);
            allConnections.add(conn);

        } catch (SQLException e) {
            throw e;
        }
    }
    public Connection getConnection() 
    {
        while (true) {
            synchronized (freeConnections) {

                if (freeConnections.size() != 0) { // free connection is  available 
                    Connection conn = freeConnections.get(0);
                    freeConnections.remove(0);
                    try {
                        conn.setAutoCommit(true);
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    return conn;
                }
                try {
                    freeConnections.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }

    }
    public void returnConnection(Connection conn)
    {
        if (null == conn) { // ignore invalid value
            return;
        }
        if (!allConnections.contains(conn)) {
            return;
        }
        synchronized (freeConnections) {

            if (freeConnections.contains(conn)) {
                return;
            }
            freeConnections.add(conn);
            freeConnections.notifyAll();
            return;
        }
    }
    public void closeAllconnections()
    {
        for (Connection conn : allConnections) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        System.out.println("ConnectionPool all connection closed");
        deregisterDriver();
    }
    public void deregisterDriver() {
        try {
            java.sql.Driver driver = DriverManager.getDriver(url);
            DriverManager.deregisterDriver(driver);
        } catch (SQLException e) {
            e.printStackTrace();
        } 
        System.out.println("ConnectionPool deregister driver");

    }
}

请帮助我理解哪里出了问题并向我解释。

1.为什么 GC 不释放或者为什么他不能做他的工作?

2.我的ConnectionPool类有问题吗?

3. 为什么 tomcat 在我的日志中没有说任何关于 OutOfMemoryException 的信息(只是崩溃)?

最佳答案

查看连接详细信息,显然您有 10 个连接,如果堆总计需要 660 MB 的 RAM,每个连接将保留 cca 66 MB。

我不知道你选择了什么数据,但是在返回连接时你可能想要关闭所有结果集和语句(你为什么要创建自己的池?dbcp、c3p0 或 commons-pool 还不够好吗?因为学习?)而且似乎还不够。我真的不知道池实现如何正确释放所有资源。

而且似乎在多个线程之间共享打开的连接并不是那么简单 Java MySQL JDBC Memory Leak所以我建议使用工作池解决方案 (dbcp)

关于Java - Tomcat GC 不会释放。总是导致崩溃,找不到任何内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48969850/

相关文章:

Android Studio 控制台输出?

java - Android 2.1 SDK + ConcurrentHashMap$ValueIterator 与 GC

java - 在实体的成员变量或 get 方法处设置 JPA 注释?

java解析html中的文本而不包含链接

java - 使用线程池时,如何让Java中的线程空闲?

java - 如何使用 Tomcat 和 IntelliJ IDEA 获取 context.xml

java - 需要帮助为 SaaS 聊天设计快速且可扩展的服务器架构

java Servlet代理不下载某些pdf文件

web-services - 我应该如何开始实现 RESTful Web 服务?

java - java中String的垃圾回收