Java HeapDump分析:String还是StringBuilder,应该使用什么?
在我的应用程序中有一个堆转储,Java HeapDump分析:String还是StringBuilder,应该使用什么?,java,string,stringbuilder,heap-memory,Java,String,Stringbuilder,Heap Memory,在我的应用程序中有一个堆转储,char[]保留的堆大约有700MB,这很奇怪(至少对我来说是这样)。同时String只有150MB 在我的应用程序中,我只使用了StringBuilder(使用默认的StringBuilder构造函数),并在添加数据时尝试避免使用String 我的问题是:我们应该一直使用StringBuilder?如果是,我们如何减少它所保留的堆?您可以使用StringInterner,它使用StringBuilder来避免不必要地创建对象。您首先用文本填充回收的StringBu
char[]
保留的堆大约有700MB,这很奇怪(至少对我来说是这样)。同时String
只有150MB
在我的应用程序中,我只使用了StringBuilder
(使用默认的StringBuilder
构造函数),并在添加数据时尝试避免使用String
我的问题是:我们应该一直使用
StringBuilder
?如果是,我们如何减少它所保留的堆?您可以使用StringInterner,它使用StringBuilder来避免不必要地创建对象。您首先用文本填充回收的StringBuilder,如果interner中有与该文本匹配的字符串,则返回该字符串(或者使用StringBuilder的toString()这样做的好处是,当您看到一个新字符串(或者至少有一个不在数组中)时,您只需创建对象(并且不超过所需),这样可以获得80%到99%的命中率,并在加载多个数据字符串时显著减少内存消耗(和垃圾)
代码:
是的,在构建字符串时始终选择
StringBuilder
——这是连接字符串的最有效但仍然很方便的方法
听起来好像有很多StringBuilder
s在等待垃圾回收。但是,为了减少堆的使用,您可以通过Threadlocal
为每个线程使用一个StringBuilder
,安全地重用StringBuilder
,即使它们不是线程安全的:
private static final ThreadLocal<StringBuilder> LOCAL_STRING_BUILDER =
ThreadLocal.withInitial(StringBuilder::new);
您最多只能拥有与线程数量相同的StringBuilder
s,而不会有那么多(可能是10到100个)
FYI
StringBuilder
在手动连接字符串时使用;这一行来源:
String str3 = str1 + str2;
将其编译为:
String str3 = new StringBuilder().append(str1).append(str2).toString();
相关:如果始终使用默认构造函数
StringBuilder
,则在填充时,它可能需要在内部继续分配更大的char[]
实例(需要大约两倍的空间,就好像用户事先知道最终的大小一样)。但可能更重要的是,当您构建最终的字符串时,必须复制StringBuilder
中的char[]
。完成附加后,您可能希望从StringBuilder
中获取完成的字符串,然后扔掉StringBuilder
。@Andy Turner:我们将所有字符串变量声明为最终变量,因为它们都是局部变量。@SauravKumarMehta:如果这就是占用空间大的原因,那么我就不必担心了,因为内存实际上是“可用的”(即使它仍然在物理内存中)因为它可以在任何必要的时候被垃圾收集。现在我们不想为第三方jar添加另一个依赖项,但看看StringInterner做了什么会很有趣吗?看看这一点,
String str3 = new StringBuilder().append(str1).append(str2).toString();