Java HeapDump Analysis:String或StringBuilder,应该使用什么?

时间:2016-05-19 09:30:17

标签: java string stringbuilder heap-memory

在我的应用程序中有一个堆转储,令人惊讶的是char[]保留的堆大约是700MB,这很奇怪(至少对我而言)。同时String只有150MB。

在我的应用程序中,我只使用了StringBuilder(使用默认的StringBuilder构造函数)并尝试避免在添加数据时使用String

我的问题是:我们应该总是选择StringBuilder吗?如果是,我们如何减少它保留的堆?

2 个答案:

答案 0 :(得分:0)

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

代码: https://github.com/OpenHFT/Java-Lang/blob/master/lang/src/main/java/net/openhft/lang/pool/StringInterner.java

答案 1 :(得分:0)

是的,在构建字符串时总是选择StringBuilder - 这是连接字符串的最有效但最方便的方法。

听起来有很多StringBuilder在等待垃圾收集。但是,为了减少堆使用,您可以安全重用您的StringBuilder即使它们不是线程安全的,通过StringBuilder每个线程使用一个Threadlocal

private static final ThreadLocal<StringBuilder> LOCAL_STRING_BUILDER =
    ThreadLocal.withInitial(StringBuilder::new);

使用示例:

public String logMessage() {
    StringBuilder sb = LOCAL_STRING_BUILDER.get();
    sb.setLength(0); // Only resets the pointer to start. Doesn't affect the backing array
    sb.append("foo=").append(myField); //etc
    return sb.toString();
}

你最多只有StringBuilder个和线程一样多,{em> 很多(可能是10's - 100's)。

无论如何,在手动连接字符串时使用

FYI StringBuilder;这一行来源:

String str3 = str1 + str2;

被编译为好像是:

String str3 = new StringBuilder().append(str1).append(str2).toString();