gpt4 book ai didi

java - 使用 StringBuffer 、 StringBuilder 、 String.intern() 优化 String 对 java 堆的使用

转载 作者:行者123 更新时间:2023-12-01 12:26:31 25 4
gpt4 key购买 nike

我正在使用 VisualVM 监控大型 java 应用程序的性能和 CPU。 当我查看其内存配置文件时,我发现最大堆(大约 50%)已被 char 数组占用。

以下是内存配置文件的屏幕截图:

enter image description here

在任何给定时间的内存配置文件中,我大约看到大约 9000 个 char[] 对象。

应用程序接受大文件作为输入。该文件大约有 80 行,每行包含 15-20 个分隔的配置选项。应用程序解析文件并将这些行存储在字符串的 ArrayList 中。然后它解析这些字符串以获取每个服务器的单独配置选项。

应用程序还经常将每个事件记录到控制台。

字符串的 Java 实现在内部使用 char[] 以及对数组和 3 个整数的引用

从互联网上的不同帖子来看, StringBuffer 、 StringBuilder 、 String.intern() 似乎是内存效率更高的数据类型。

它们与 java.lang.String 相比如何?有人对它们进行过基准测试吗?如果应用程序使用多线程(确实如此),它们是安全的替代方案吗?

最佳答案

我所做的是拥有一个或多个字符串池。我这样做是为了 a) 如果池中有字符串,则不创建新字符串;b) 减少保留的内存大小,有时减少 3-5 倍。您可以自己编写一个简单的字符串内部,但我建议您首先考虑如何读取数据以确定最佳解决方案。这很重要,因为如果没有有效的解决方案,很容易使事情变得更糟。

正如 EJP 指出的那样,一次处理一行效率更高,就像在阅读时解析每一行一样。即 intdouble 占用的空间比相同的 String 少得多(除非您的重复率非常高)

<小时/>

这是一个 StringInterner 的示例,它采用 StringBuilder 来避免不必要地创建对象。首先用文本填充回收的 StringBuilder,如果内部存在与该文本匹配的 String,则返回该 String(或者 StringBuilder 的 toString() )。好处是您只创建对象(并且不超过当你看到一个新的字符串(或者至少一个不在数组中的字符串)时,这可以得到 80% 到 99% 的命中率,并在加载许多数据字符串时显着减少内存消耗(和垃圾)。

public class StringInterner {
@NotNull
private final String[] interner;
private final int mask;

public StringInterner(int capacity) {
int n = nextPower2(capacity, 128);
interner = new String[n];
mask = n - 1;
}

@Override
@NotNull
public String intern(@NotNull CharSequence cs) {
long hash = 0;
for (int i = 0; i < cs.length(); i++)
hash = 57 * hash + cs.charAt(i);
int h = hash(hash) & mask;
String s = interner[h];
if (isEqual(s, cs))
return s;
String s2 = cs.toString();
return interner[h] = s2;
}

static boolean isEqual(@Nullable CharSequence s, @NotNull CharSequence cs) {
if (s == null) return false;
if (s.length() != cs.length()) return false;
for (int i = 0; i < cs.length(); i++)
if (s.charAt(i) != cs.charAt(i))
return false;
return true;
}

static int nextPower2(int n, int min) {
if (n < min) return min;
if ((n & (n - 1)) == 0) return n;
int i = min;
while (i < n) {
i *= 2;
if (i <= 0) return 1 << 30;
}
return i;
}

static int hash(long n) {
n ^= (n >> 43) ^ (n >> 21);
n ^= (n >> 15) ^ (n >> 7);
return (int) n;
}
}

这个类很有趣,因为它在传统意义上不是线程安全的,但在并发使用时可以正常工作,事实上,当多个线程对数组内容有不同的 View 时,它可能会更有效地工作。

关于java - 使用 StringBuffer 、 StringBuilder 、 String.intern() 优化 String 对 java 堆的使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26290043/

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