2010-08-24 104 views
3

以下代码在运行jdk1.6.0_14的Linux 3.5企业版框中抛出OutofMemoryError,但在JDK 1.6.0_20上运行正常我无言以对,它发生了。超过GCOverhead限制

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的是罪魁祸首,但不当然。如何解决这个问题?

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

+0

我怀疑在两个JVM上通过Xmx分配给堆的内存是不同的?或者JDK 1.6_20以-XX启动:-UseGCOverheadLimit? – JoseK 2010-08-24 05:56:21

+0

实际上在Windows上分配的内存仅为512M,而在Linux上则为1024M。不,Windows上的JDK不是以-XX开头的:-UseGCOverheadLimit选项。 – Amit 2010-08-24 07:29:57

+1

就我个人而言,我不会在循环中抛弃'StringBuilder',而只需通过调用['setLength(0)']来清除它(http://download.oracle.com/javase/6/docs/api/java /lang/StringBuilder.html#setLength(int))这种方式缓冲区不需要每次重新分配。频繁的分配和解除分配是“GCOverhead Limit exceeded”问题的共同目标。 – 2010-08-24 07:46:25

回答

2

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

-XX:+UseGCOverheadLimit -Use a policy that limits the proportion of the VM's time that is spent in GC before an OutOfMemory error is thrown. (Introduced in 6.)

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

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

  • 启动时明确设置堆大小-Xmx和-Xms选项JVM。如果您已经这样做了(在较旧的JVM上),请增加数字以使最大堆大小更大。

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

如果这个问题只发生在你的服务器运行了一段时间之后,那么也许你有内存泄漏。

+0

谢谢Andreas。我改变了命令来运行我的程序如下: 的java -server -Xms100m -Xmx1024M -XX:-UseGCOverheadLimit -XX:+ UseConcMarkSweepGC 这导致程序正常工作了一段时间,但后来未能与以下OutOfMamoryError: 异常线程 “main” 的Java。 lang.OutOfMemoryError:Java堆空间 在java.util.Arrays.copyOf(Arrays.java:2786) .... 看起来像java选项以外的代码也有问题。由于物理内存限制,我无法将1400M分配给堆。 – Amit 2010-08-24 07:32:11

0

垃圾收集已使用JDK 1.6.0_18显著改善:

In the Client JVM, the default Java heap configuration has been modified to improve the performance of today's rich client applications. Initial and maximum heap sizes are larger and settings related to generational garbage collection are better tuned.

就让我们来看看在这个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字节,它是在左justfied clobLimit。我不知道,并试图

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

输出功率为

1234567890 

为了实现你的意见告诉什么,你可以用简单的形式:

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

这看起来正确,因为应用程序在1.6.0_20上运行良好。我会尝试在Linux机器上安装最新的JDK,尽管它不在我的手中:( – Amit 2010-08-24 07:34:11

+0

我在代码中有一些东西可以改进以解决这个问题? – Amit 2010-08-24 10:03:25

+0

Ya注释verbiage是误导。其实getCLOBString(rs ,tabMeta)方法本身只提取“clobLimit”字符数,String.format已被用来确保正确的paddin使一列的所有值长度相等 – Amit 2010-08-25 09:56:33