超出GC开销限额

时间:2010-08-24 05:24:26

标签: java out-of-memory

以下代码在运行jdk1.6.0_14的Linux 3.5企业版上抛出OutofMemoryError,但在JDK 1.6.0_20上正常运行我无能为力。为什么会发生这种情况。

while (rs.next()) {
  for (TableMetaData tabMeta : metaList) {
rec.append(getFormattedString(rs, tabMeta));
  }
  rec.append(lf);
  recCount++;
  if (recCount % maxRecBeforWrite == 0) {
    bOutStream.write(rec.toString().getBytes());
    rec = null;
    rec = new StringBuilder();
  }
}
bOutStream.write(rec.toString().getBytes());

getFormattedString()方法在这里:

private String getFormattedString(ResultSet rs, TableMetaData tabMeta)
        throws SQLException, IOException {

    String colValue = null;
    // check if it is a CLOB column
    if (tabMeta.isCLOB()) {
        // Column is a CLOB, so fetch it and retrieve first clobLimit chars.
        colValue = String.format("%-" + clobLimit + "s", getCLOBString(rs,
                tabMeta));
    } else {
        colValue = String.format("%-" + tabMeta.getColumnSize() + "s", rs
                .getString(tabMeta.getColumnName()));
    }
    return colValue;
}

以下是异常追踪:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
        at java.util.Formatter$FormatSpecifier.justify(Formatter.java:2827)
        at java.util.Formatter$FormatSpecifier.print(Formatter.java:2821)
        at java.util.Formatter$FormatSpecifier.printString(Formatter.java:2794)
        at java.util.Formatter$FormatSpecifier.print(Formatter.java:2677)
        at java.util.Formatter.format(Formatter.java:2433)
        at java.util.Formatter.format(Formatter.java:2367)
        at java.lang.String.format(String.java:2769)
        at com.boa.cpal.cpal2repnet.main.CPALToReportNet.getFormattedString(Unknown Source)

我怀疑使用String.format是罪魁祸首,但不确定。如何克服这个问题?

请注意,此代码已写入数据库中的查询,该数据库具有巨大的表来读取结果集并创建具有特定格式的提取文件。

2 个答案:

答案 0 :(得分:2)

您获得的异常是指此HotSpot选项启用的GC开销限制:

  

-XX:+ UseGCOverheadLimit - 使用一种策略来限制在引发OutOfMemory错误之前在GC中花费的VM时间的比例。 (6。引入。)

所以,我最好的猜测是你的应用程序只是耗尽堆空间。正如@ Andreas_D的回答所说,默认堆大小在jdk1.6.0_14和JDK 1.6.0_20之间改变,这可以解释不同的行为。您的选择是:

  • 升级到更高版本的JVM。 ( UPDATE - 2012/06 甚至JDK 1.6.0_20现在已经过时了。后来1.6和1.7版本有很多安全修复程序。)

  • 启动JVM时,显式设置堆维度-Xmx和-Xms选项。如果您已经在执行此操作(在较旧的JVM上),请增加数字以使最大堆大小更大。

您还可以调整GC开销限制,但这在生产服务器上可能不是一个坏主意。

如果这个特殊问题只发生在服务器运行一段时间之后,那么可能是内存泄漏了。

答案 1 :(得分:0)

JDK 1.6.0_18:

显着改善了垃圾收集
  

在客户端JVM中,已修改默认Java堆配置以提高当今富客户端应用程序的性能。初始和最大堆大小更大,并且更好地调整与分代垃圾收集相关的设置。

快速查看此release notes中的详细信息让我相信这就是为什么1.6.0_20的问题较少。


以下部分代码与评论不一致:

// Column is a CLOB, so fetch it and retrieve first clobLimit chars.
colValue = String.format("%-" + clobLimit + "s", getCLOBString(rs, tabMeta));

colValue没有从CLOB获得第一个clobLimit个字节,它在 clobLimit处被选中。我不确定并尝试过

 System.out.println(String.format("%-5s", "1234567890"));

,输出

 1234567890

要实现您在评论中所说的内容,您可以使用更简单的形式:

colValue = getCLOBString(rs, tabMeta).substring(0, clobLimit);