当前位置: 首页 > 知识库问答 >
问题:

JdbcRowSet中的内存泄漏

戚研
2023-03-14

我尝试用一个大表(大约一万条记录)中的记录填充JdbcRowSet。我尝试了两个变体(参见下面的代码):

  1. 创建连接对象,使用JdbcRowSetImpl(connection)实例化,在循环中执行查询。
  2. 使用JdbcRowSetImpl(DriverManager.GetConnection(“jdbc:....”)实例化,在循环中执行查询。

第一个变体会导致内存泄漏,直到堆满为止。第二个变体没有内存泄漏。有人能解释一下为什么第一个会在重用连接对象时导致内存泄漏吗?

谢谢

%1的代码。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.sql.rowset.JdbcRowSet;
import com.sun.rowset.JdbcRowSetImpl;

public class JdbcRowSetMemoryLeak {

/**
 * @param args
 */
public static void main(String[] args) {
    String username = "user";
    String password = "password";
    Connection connection = null;
    try {
        Class.forName("com.mysql.jdbc.Driver");
        connection = DriverManager.getConnection("jdbc:mysql://localhost/db_ams?user=" + username + "&password=" + password);
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
    JdbcRowSet jdbcRS = null;
    for (int i=0;i<150;i++){
        System.out.println(i);
        try {
            jdbcRS = new JdbcRowSetImpl(connection); // <-- Memory is leaking
            jdbcRS.setCommand("Select * from sample_t;");
            jdbcRS.execute();
//              jdbcRS.close(); <-- Returns a null pointer Exception
            jdbcRS = null;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

}

%2的代码。

import java.sql.DriverManager;
import java.sql.SQLException;
import javax.sql.rowset.JdbcRowSet;
import com.sun.rowset.JdbcRowSetImpl;

public class JdbcRowSetMemoryGood {

/**
 * @param args
 */
public static void main(String[] args) {
    String username = "user";
    String password = "password";
    try {
        Class.forName("com.mysql.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    JdbcRowSet jdbcRS = null;
    for (int i=0;i<150;i++){
        System.out.println(i);
        try {
            jdbcRS = new JdbcRowSetImpl(DriverManager.getConnection("jdbc:mysql://localhost/db_ams?user=" + username + "&password=" + password));
            jdbcRS.setCommand("Select * from sample_t;");
            jdbcRS.execute();
            jdbcRS.close();
            jdbcRS = null;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

}

共有1个答案

丁昌翰
2023-03-14

您的问题“为什么在重用连接对象时第一个会导致内存泄漏?”的答案

是的,您正在重用connection对象,但您在每次迭代中都创建一个新的jdbcrowset对象,而您没有关闭它,这会导致内存泄漏。jdbcrs=null;不会关闭资源。

您的问题“为什么我不能在第一个snippset中关闭ResultSet而在第二个snippset中关闭?”的答案

在第一个代码段中,当您使用close方法关闭jdbcrs对象jdbcrs时,jdbcrs.close();也关闭了连接。因此,第二次迭代将抛出一个NullPointerException,因为在jdbcrs=new JdbcRowSetImpl(connection);处,connection已经关闭。

第二个代码段工作良好,因为您在getConnection方法的每次迭代中都创建一个新连接。

最好的方法是使用cachedrowset在每次迭代后自动关闭资源:

package databases;
import java.sql.SQLException;
import javax.sql.rowset.*;

public class CachedRowSet_Usage {

    public static void main(String[] args) {
        String username = "username";
        String password = "password";
        String url = "jdbc:mysql://localhost:3306/your_database_name"; 

        try{
            CachedRowSet rs = RowSetProvider.newFactory().createCachedRowSet();
            //JdbcRowSet rs = RowSetProvider.newFactory().createJdbcRowSet();
            rs.setUrl(url);
            rs.setUsername(username);
            rs.setPassword(password);

            for(int i=0;i<150;i++){
                System.out.println(i);
                rs.setCommand("Select * from your_table");
                rs.execute();  
                //rs.close();  <-- no use, rs closes automatically
            }
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
 类似资料:
  • 我有一个在Tomcat7上运行的web应用程序的问题。 当我尝试重新启动web应用程序时,我在servlet内部创建的线程打开的端口仍然是打开的。 “http-bio-8080-acceptor-0”后台进程prio=10 tid=0x00007F4ED4206000 nid=0x71f0 runnable[0x00007F4ECC78F000]java.lang.thread.state:run

  • 我在Tomcat中得到了threadlocal内存泄漏错误,我正在使用ThreadPool,但在我的WebApp中没有threadlocal的实现。 严重:web应用程序[/mywebapp]创建了一个ThreadLocal,其键类型为[org.a pache.http.impl.cookie.dateformatholder$1](值为[org.apache.http.imp l.cookie.

  • 本文向大家介绍浅析Java中的内存泄漏,包括了浅析Java中的内存泄漏的使用技巧和注意事项,需要的朋友参考一下 ava最明显的一个优势就是它的内存管理机制。你只需简单创建对象,java的垃圾回收机制负责分配和释放内存。然而情况并不像想像的那么简单,因为在Java应用中经常发生内存泄漏。 本教程演示了什么是内存泄漏,为什么会发生内存泄漏以及如何预防内存泄漏。 什么是内存泄漏? 定义:如果对象在应用中

  • 当关闭Tomcat时,我得到以下错误: 严重:web应用程序[App]创建了一个ThreadLocal,其键类型为[org.apache.logging.log4j.core.layout.PatternLayout$1](值为[org.apache.logging.log4j.core.layout.PatternLayout$1@14391AAF]),值类型为[java.lang.String

  • 我写了一段代码,让字母在我写的时候出现并飞行。这个问题消耗了大量的内存。 我已经优化了一点 在侦听器中共享对象并更新其参数。 每次打印新字母时调用 gc 但是它仍然使用大量的内存,所以有什么想法来降低它的内存利用率吗? 提前致谢。 操作系统:Arch Linux 64位平台:英特尔i7-第三代,8 GB内存IDE : Intellij JDK : 1.8.0_102

  • 问题内容: 我认为我的android应用正在泄漏内存。我不是绝对确定这是问题所在。 应用程序打开时经常崩溃,并且logcat尝试加载位图图像时会显示“内存不足”异常。 崩溃后,我重新打开了该应用程序,它运行正常。Logcat会显示许多“ gc”,并且JIT表会不时地向上调整大小,而不会向下调整,直到应用程序因内存不足错误而崩溃。 这听起来像是内存泄漏吗?如果是这样,我该如何定位和关闭泄漏点。 这是