重复的replace调用会导致java.lang.OutOfMemoryError

重复的replace调用会导致java.lang.OutOfMemoryError,java,regex,performance,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

我正在大量处理非常大的文件。我在每行的每个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)
线程“main”java.lang.OutOfMemoryError中出现异常:超出GC开销限制 Pattern$BnM.optimize(Pattern.java:5411) 位于java.util.regex.Pattern.compile(Pattern.java:1711) Pattern.(Pattern.java:1351) 位于java.util.regex.Pattern.compile(Pattern.java:1054) 替换(String.java:2239) 在XYZ.shortenUri(XYZ.java:217) 我确实增加了
Xms
Xmx
,但没有帮助。奇怪的是,在监视进程时,我也无法观察到内存使用量的增加。关于提高性能和内存消耗有什么建议吗?

引用自:

GC时间过长和OutOfMemory错误

如果在垃圾收集中花费的时间太多,并行收集器将抛出OutOfMemoryError:如果在垃圾收集中花费的时间超过总时间的98%,而堆的恢复时间少于2%,则将抛出OutOfMemoryError。此功能旨在防止应用程序在运行较长时间的同时由于堆太小而进展甚微或毫无进展。如有必要,可通过在命令行中添加选项-XX:-usegcoveredlimit来禁用此功能

  • 您可以尝试的第一件事是进一步增加堆大小,例如,使用
    -Xmx4G
    将堆大小增加几GB

  • 另一个选项可能是通过不使用
    replace
    方法来防止创建过多的对象。相反,您可以根据需要创建
    模式
    匹配器
    对象(见下文)

  • 我看到的第三个选项是使用
    -XX:-usegcoveredlimit

    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:");
    }
    

  • 您正在测试的
    uri
    的原始值是多少?只是一个较长的uri,例如
    http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral
    这可能是因为容器上的传入线程太多的问题吗?那么,您可以将这4个替换操作合并为1:
    return uri.replaceAll(“http://(?:purl\\\.org/(dc)/|(b))abel(n)et\\\.org/rdf/| www\\.(?:lemon model\\.net/(lemon)| w3\\.org/1999/02/22-(rdf)-语法ns)#“,“$1$2$3$4$5:”
    replace
    无论如何都是基于regex的,为什么不直接使用regex呢。因为每个
    replace
    都会创建并返回与调用它的原始字符串大小相似的新字符串,如果有许多
    replace
    调用,那么每个调用都会创建自己的大字符串。我的不速之客是,如果你经常调用这个方法,你的内存可能会被那些临时字符串填满,比GC清除它们的速度还要快。如果我的猜测接近于真,考虑使用一些类似的东西来避免有很多代码>替换< /代码>调用。