- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 VisualVM 监控大型 java 应用程序的性能和 CPU。 当我查看其内存配置文件时,我发现最大堆(大约 50%)已被 char 数组占用。
以下是内存配置文件的屏幕截图:
在任何给定时间的内存配置文件中,我大约看到大约 9000 个 char[] 对象。
应用程序接受大文件作为输入。该文件大约有 80 行,每行包含 15-20 个分隔的配置选项。应用程序解析文件并将这些行存储在字符串的 ArrayList 中。然后它解析这些字符串以获取每个服务器的单独配置选项。
应用程序还经常将每个事件记录到控制台。
字符串的 Java 实现在内部使用 char[] 以及对数组和 3 个整数的引用。
从互联网上的不同帖子来看, StringBuffer 、 StringBuilder 、 String.intern() 似乎是内存效率更高的数据类型。
它们与 java.lang.String 相比如何?有人对它们进行过基准测试吗?如果应用程序使用多线程(确实如此),它们是安全的替代方案吗?
最佳答案
我所做的是拥有一个或多个字符串池。我这样做是为了 a) 如果池中有字符串,则不创建新字符串;b) 减少保留的内存大小,有时减少 3-5 倍。您可以自己编写一个简单的字符串内部,但我建议您首先考虑如何读取数据以确定最佳解决方案。这很重要,因为如果没有有效的解决方案,很容易使事情变得更糟。
正如 EJP 指出的那样,一次处理一行效率更高,就像在阅读时解析每一行一样。即 int
或 double
占用的空间比相同的 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/
为什么下一行没有给出编译时错误? StringBuffer sb = new StringBuffer(new StringBuffer()); 我在网上查了很多也找不到原因。不仅如此,它还允许 St
我在 http get 请求中使用了下面的代码,但是我从返回中得到的是 null。我不知道为什么。 public static String getResponseFromGetUrl(Strin
错误是: Unreachable statement in line StringBuffer buffer = new StringBuffer() 这是我的代码: public void
当 StringBuffer 超出容量时,是否会创建一个新的 StringBuffer 对象,还是仍然是旧的? class Test{ public static void main(String[]
1.我对这两者感到困惑,如果有的话,它们有不同的功能吗? StringBuffer(CharSequence chars) 和 StringBuffer(String str) 2。 String 和
阅读本文后 - What does 'synchronized' mean?我仍然无法理解为什么 StringBuffer 在线程安全环境中会比 StringBuilder 慢。 StringBuff
考虑以下代码 final class immudemo { private static final StringBuffer bf = new StringBuffer("Yaxita"
Groovy支持用于创建StringBuilder / StringBuffer的文字语法,而不是通常的语法 def sb = new StringBuilder() 但是,我似乎无法记住(或在Goo
这是我尝试使用数组构建 stringBuffer。我该如何解决这个问题? import java.util.ArrayList; public class StringBufferProj { pub
我对官方 Javadoc 的说法感到困惑 public StringBuffer replace(int start, int end, String str) Replaces the charac
与将所有数组项附加到 StringBuffer 然后打印相比,为什么在循环中打印数组项需要更多时间? 在此,我在循环中打印了数组项。 public static void main (String[]
我目前正在使用很多这样的内容来重构应用程序: StringBuffer buff1 = new StringBuffer(""); buff1.append("some value A"); buff
我有一个简单的函数,用于连接到服务器并将响应作为字符串返回。当返回的数据量较小但响应较大时,它可以正常工作。它不会完整存储服务器返回的响应字符串,并以...结尾。令人惊讶的是,system.out.p
我对编程还很陌生,需要一些帮助。我正在学习如何使用 StringBuffer 类,并且编写了一个简单的代码。但是,当我尝试运行该程序时,我不断收到错误消息“找不到符号”。任何建议都会很棒!谢谢! pu
在ArrayList中,添加操作是摊销操作。因此,在阅读 StringBuffer 时,我想到了为什么 StringBuffer 不进行摊销。假设我对字符串缓冲区对象使用追加操作,那么它应该能够在其底
我正在尝试在字符串中切换 $ 及其右侧的字符。我不允许使用 char[],所以我决定使用 StringBuffer。但是,当我尝试使用 H$E 之类的内容运行代码时,它会输出 HE$H$E 我不知道额
这个问题已经有答案了: Difference between StringBuilder and StringBuffer (33 个回答) 已关闭 9 年前。 很多人都提到过Java中StringB
我正在尝试从InputStream 中读取一些数据,然后将它们放入StringBuffer 中进行打印。 我把这段代码放在main方法中。 我的问题是,只有在调试代码时才打印 StringBuffer
我正在运行此代码: public class testttt { public static void main(String[] args){ ArrayList listOne = new
我有以下代码: public class MyLogger { private StringBuilder logger = new StringBuilder(); public voi
我是一名优秀的程序员,十分优秀!