重复的替换调用导致java.lang.OutOfMemoryError

时间:2019-10-26 12:38:21

标签: java regex performance

我正在大量处理非常大的文件。我在每行的每个URI上调用以下方法:

public String shortenUri(String uri) {
    uri = uri
            .replace("http://www.lemon-model.net/lemon#", "lemon:")
            .replace("http://babelnet.org/rdf/", "bn:")
            .replace("http://purl.org/dc/", "dc:")
            .replace("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf:");
    return uri;
}

奇怪的是,这导致以下错误:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.regex.Pattern$BnM.optimize(Pattern.java:5411)
at java.util.regex.Pattern.compile(Pattern.java:1711)
at java.util.regex.Pattern.<init>(Pattern.java:1351)
at java.util.regex.Pattern.compile(Pattern.java:1054)
at java.lang.String.replace(String.java:2239)
at XYZ.shortenUri(XYZ.java:217)

我确实提高了XmsXmx,但没有帮助。奇怪的是,在监视进程时,我也没有观察到内存使用率的增加。对提高性能和内存消耗有什么建议吗?

1 个答案:

答案 0 :(得分:0)

来自Oracle的引用:

  

GC时间过多和内存不足错误

     

如果在垃圾回收上花费了太多时间,则并行收集器将抛出OutOfMemoryError:如果在垃圾回收中花费了总时间的98%以上,并且回收的堆少于2%,则将发生OutOfMemoryError抛出。此功能旨在防止应用程序长时间运行,而由于堆太小而几乎没有进展,甚至没有进展。如有必要,可以通过在命令行中添加选项-XX:-UseGCOverheadLimit来禁用此功能。

  1. 您可以尝试做的第一件事是进一步增加堆大小,例如,使用-Xmx4G增大几GB。
  2. 另一种选择可能是通过不使用replace方法来防止创建太多对象。相反,您可以根据需要创建PatternMatcher对象(请参见下文)。
  3. 我看到的第三个选项是与-XX:-UseGCOverheadLimit完全禁用此功能

    private static final Pattern PURL_PATTERN = Pattern.compile("http://purl.org/dc/");
    // other patterns
    
    public static String shortenUri(String uri) {
        // other matchers
        Matcher matcher = PURL_PATTERN.matcher(uri);
        return matcher.replaceAll("dc:");
    }