gpt4 book ai didi

java - 通过子字符串解析后如何回收内存?实习生()还是新字符串()?

转载 作者:IT老高 更新时间:2023-10-28 20:54:19 24 4
gpt4 key购买 nike

短版:如果调用string.substring(n,m).intern(),字符串表是保留子字符串还是保留原字符串?

...但我不确定这是一个正确的问题,所以这里是长版本:

我正在使用遗留 Java 代码 (PCGen),它通过将每个文件作为一个大字符串来解析文件,然后使用 String.split、.trim、.substring 和 StringTokenizer 将它们分解为 token 。这对于解析非常有效,因为这些方法都不会复制原始字符串,而是都指向共享 char[] 的一部分。

解析结束后,我想回收一些内存。只需要原始大字符串的几个小子字符串,但强引用阻止了大字符串被收集。后来我遭受了 OOM,我相信部分原因是大量已解析文件的巨大堆影响。

我知道我可以通过 new String(String)(copy-on-write) 修剪大字符串。而且我知道我可以通过 String.intern 减少字符串重复(这很重要,因为解析的文件中有很多冗余)。我需要同时使用两者来回收最大数量的堆,还是 .intern() 两者都做?阅读 OpenJDK7 热点源代码(hotspot/src/share/vm/classfile/symbolTable.cpp),看起来字符串表保留了整个字符串,并且根本没有修剪它的偏移量/长度。所以我想我需要制作一个新的字符串,然后实习这个结果。对吧?

话虽如此,切换到流式解析器在内存方面将是一个巨大的胜利,但对于短期而言这变化太大了。

最佳答案

您可以使用 new String(String) 和 intern() 方法,这将根据 Java 7 update 4 的要求进行复制。从 Java 7 update 5 开始,子字符串将获得更深的副本,但您可能仍需要使用实习生()。注意:Java 7 使用堆而不是 perm gen 来存储字符串文字。

public static void main(String[] args) {
char[] chars = new char[128];
Arrays.fill(chars, 'A');
String a128 = new String(chars);
printValueFor("a128", a128);
String a16 = a128.substring(0, 16);
printValueFor("a16", a16);
}

public static void printValueFor(String desc, String s) {
try {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
char[] valueArr = (char[]) value.get(s);
System.out.println(desc + ": " + Integer.toHexString(System.identityHashCode(valueArr)) + ", len=" + valueArr.length);
} catch (Exception e) {
throw new AssertionError(e);
}
}

在 Java 7 更新 4 上打印

a128: 513e86ec, len=128
a16: 53281264, len=16

我希望 Java 6 不会这样做。

关于java - 通过子字符串解析后如何回收内存?实习生()还是新字符串()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14516635/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com