简体   繁体   English

Java HeapDump分析:String或StringBuilder,应使用什么?

[英]Java HeapDump Analysis: String or StringBuilder, what should be used?

In my application there was a heap dump and surprisingly heap retained by char[] was around 700MB, which was strange (at least for me). 在我的应用程序中,有一个堆转储,令人惊讶的是char[]保留的堆约为700MB,这很奇怪(至少对我而言)。 At the same time String had only 150MB. 同时, String只有150MB。

In my application, I have only used StringBuilder (using default StringBuilder constructor) and tried to avoid using String as we were appending data. 在我的应用程序中,我仅使用StringBuilder (使用默认的StringBuilder构造函数),并尝试在添加数据时避免使用String

My question here is: Should we always go for StringBuilder ? 我的问题是:我们是否应该一直使用StringBuilder And if yes, how can we reduce the heap retained by it? 如果是,我们如何减少它保留的堆?

Possibly you can use StringInterner which takes a StringBuilder to avoid creating objects needlessly.You first populate a recycled StringBuilder with the text and if a String matching that text is in the interner, that String is returned (or a toString() of the StringBuilder is.) The benefit is that you only create objects (and no more than needed) when you see a new String (or at least one not in the array) This can get a 80% to 99% hit rate and reduce memory consumption (and garbage) dramatically when loading many strings of data. 可能您可以使用StringInterner来获取一个StringBuilder以避免不必要地创建对象。您首先用文本填充一个回收的StringBuilder,并且如果匹配器中的文本与该文本匹配,则返回该String(或StringBuilder的toString()为。)的好处是,仅当您看到一个新的String(或至少一个不在数组中的字符串)时才创建对象(且不超过所需数量),这可以使命中率达到80%至99%,并减少内存消耗(并且垃圾),当加载许多数据字符串时会产生很大的影响。

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

Yes, always go for StringBuilder when building strings - it's the most efficient, but still convenient, way of concatenating strings. 是的,在构建字符串时,请始终使用StringBuilder这是连接字符串的最有效但仍最方便的方法。

It sounds like there are lots of StringBuilder s hanging around waiting to be garbage collected. 听起来好像有很多StringBuilder徘徊在等待被垃圾收集。 However, to reduce heap usage, you can safely reuse your StringBuilder s even though they are not threadsafe by using one StringBuilder per thread via Threadlocal : 但是,为了减少堆使用量,即使每个线程都不安​​全,也可以通过Threadlocal通过每个线程使用一个StringBuilder来安全地重用 StringBuilder

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

Example usage: 用法示例:

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();
}

You will only ever have at most as many StringBuilder s as there are threads, which won't be that many (maybe 10's - 100's). 您最多只能拥有与线程数一样多的StringBuilder ,而线程数则不会那么多(也许是10到100)。


FYI StringBuilder is used when concatenating strings manually anyway; 无论如何,当手动连接字符串时,将使用FYI StringBuilder this line of source: 该行代码:

String str3 = str1 + str2;

gets compiled as if it were: 被编译为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM