java.lang.OutOfMemoryError从一个大的表读取时(java.lang.OutO

2019-09-17 22:52发布

我试图预先生成一个非常大的表(300GB)在PostgreSQL的报告。 我做这样的事情:

rs = stmt.executeQuery("SELECT * FROM tbl");
System.out.println("select all finished");
while (rs.next()) {
    /* generate report and save it in report table */
    /* generated reports are not in memory, 
     * They are saved in a summary table in each iteration */
}

当我启动应用程序它给Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 。 我试图用stmt.setFetchSize(1000)但它并没有解决问题。

解决办法是什么? 我使用Debian的6.0.5和OpenJDK的6 PostgreSQL的8.4.11。

[UPDATE]

打印的纸叠跟踪显示OutOfMemoryError异常已被生成rs = stmt.executeQuery("SELECT * FROM tbl"); 线。 另外System.out.println("select all finished"); 从来没有显示。

  1. 我在运行的autocommit模式。
  2. stmt.getResultSetConcurrency()返回1007。
  3. stmt.getResultSetHoldability()返回2。
  4. rs.getType()返回1003。

Answer 1:

这个问题可能是PostgreSQL只使用fetchSize在狭窄的一些情况。 请参阅: http://jdbc.postgresql.org/documentation/91/query.html#fetchsize-example

  • 到服务器的连接必须是使用V3协议。 这是默认的(并且只受支持)服务器版本7.4及更高版本。
  • 该连接不能在自动提交模式。 后端在交易结束时关闭游标,所以在自动提交模式,后端将已关闭任何东西之前光标可以从中获取。
  • 该语句必须以ResultSet类型ResultSet.TYPE_FORWARD_ONLY的创建。 这是默认的,所以没有代码需要重写,以利用这一优势,但它也意味着你不能向后滚动或以其他方式ResultSet中跳来跳去。
  • 给出的查询必须是单个语句,用分号串成不是多个语句。

所以,如果你在执行此自动提交,或比其他结果集类型TYPE_FORWARD_ONLY PostgreSQL将获取所有行。 也正看着PostgreSQL的JDBC驱动程序9.0-801它看起来像使用可保持结果集也将使其获取所有行的来源。



Answer 2:

我不认为你有什么存在会导致那种错误的。 我相信,垃圾收集器,通过一起为您的迭代来rs.next()所以你不应该有内存问题。 它可能有事情做与你试图对结果集做什么。 不知道你在做什么,虽然,我只能猜测你想要的一切存储在内存中的对象。 所以,如果你将值存储到一个StringBuilder或东西,将是一个问题。 我建议把结果写入磁盘,当您去,而不是试图收集所有到内存中的对象(再次,我只是猜测你在做什么,因为你没有提供这方面的信息)。 在Java助手图书馆 ,有一个resultSetToCSVFile(ResultSet rs, String destination)方法,你可能会发现有用的。 处理这种方式阻止你拿着它都在内存中,但你可以写你想的报告。 顺便说,要做到这一点,你需要包括opencsv库 。 或者你可以只通过包括直接调用该方法的Java助手库 。

 /**
   * Prints the given ResultSet to a comma separated file (the destination)
   *
   * @param rs
   * @param destination
   * @throws SQLException
   * @throws FileNotFoundException
   */
  public static void resultSetToCSVFile(ResultSet rs, String destination) throws SQLException, FileNotFoundException, IOException {
    ResultSetMetaData metaData = rs.getMetaData();
    int columnCount = metaData.getColumnCount();
    String[] header = new String[columnCount];
    for (int i = 0; i < columnCount; i++) {
      header[i] = metaData.getColumnName(i + 1);
    }
    File file = new File(destination);
    IOHelper.checkDirectory(file);
    try (PrintWriter pw = new PrintWriter(file); CSVWriter writer = new CSVWriter(pw)) {
      writer.writeNext(header);
      while (rs.next()) {
        String[] row = new String[columnCount];
        for (int i = 0; i < columnCount; i++) {
          String string = rs.getString(i + 1);
          if (string == null) {
            string = "";
          }
          row[i] = string;
        }
        writer.writeNext(row);
      }
    }
  }


文章来源: java.lang.OutOfMemoryError when reading from a large table