![](/img/trans.png)
[英]OutOfMemoryError in StringBuilder.append() even with more than enough memory
[英]StringBuilder uses more memory when append is used
{
StringBuilder fileBuff = new StringBuilder();
long before = getUsedMem();
try {
//Open InputStreamReader here
while ((currLine = lnr.readLine()) != null) {
fileBuff.append("\r\n" + currLine);
}
//Close streams
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("usedTotal: " + (getUsedMem() - before));
}
private long getUsedMem() {
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
在運行代碼幾次時,我得到usedTotal ~ 14279888 ,但是如果我用fileBuff.append("\\r\\n").append(currLine)
替換fileBuff.append("\\r\\n").append(currLine)
我的內存幾乎fileBuff.append("\\r\\n").append(currLine)
了一倍~ 33264440 。
有人可以解釋原因,因為我知道String
連接也使用StringBuilder
?
我:fileBuff.append(“\\ r \\ n”+ currLine);
62: aload 6
64: invokevirtual #16 // Method java/io/LineNumberReader.readLine:()Ljava/lang/String;
67: dup
68: astore_2
69: ifnull 99
72: aload_1
73: new #2 // class java/lang/StringBuilder
76: dup
77: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
80: ldc #17 // String \r\n
82: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
85: aload_2
86: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
89: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
92: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
95: pop
96: goto 62
II fileBuff.append(“\\ r \\ n”)。append(currLine)
62: aload 6
64: invokevirtual #16 // Method java/io/LineNumberReader.readLine:()Ljava/lang/String;
67: dup
68: astore_2
69: ifnull 86
72: aload_1
73: ldc #17 // String \r\n
75: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
78: aload_2
79: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
82: pop
83: goto 62
顯然#II應該使用更少的內存,但事實並非如此。 我正在閱讀的文件是50k長。
使用StringBuilder
您需要預留空間來向緩沖區添加字符串。 這是使用StringBuilder
而不是string的一個很好的例子,因為你正在使用while循環。
當你使用String
,每次輸入如下內容:
String s = s + someOtherString;
你丟棄現有的s
字符串並創建一個新字符串而不是s + someOtherString
。 這意味着你經常需要新的內存來制作連接的字符串,拋出舊的字符串,並將變量的引用放到新的字符串中。
使用StringBuilder
您可以附加到字符串,而無需刪除現有部分。
所以是的,它使用了更多的內存,但與僅使用字符串相比,它在某些情況下非常有效。
換句話說: String
是一個不可變對象,而StringBuilder
則不是。
在你的代碼中:
fileBuff.append("\r\n" + currLine);
這與new String("\\r\\n" + currLine);
這是1個String對象
你正在使用1追加。
在你的評論中你說如果你使用這個:
fileBuff.append("\r\n").append(currLine);
這與new String("\\r\\n");
和new String(currLine);
這是2個String對象
你幾乎翻了一倍的記憶。 這是有道理的,因為你正在進行2次附加,因此使用了兩倍的內存。
我想寫這篇關於@JRENs答案的評論,但我沒有足夠的代表。 2個追加的原因需要更多內存,請訪問http://docs.oracle.com/javase/tutorial/java/data/buffers.html
String中不可用的StringBuilder上的主要操作是append()和insert()方法,它們被重載以接受任何類型的數據。 每個都將其參數轉換為字符串,然后將該字符串的字符追加或插入字符串生成器中的字符序列。
因此,每個追加操作都會創建一個新的String,這就是為什么2個追加(每個循環)占用的內存大約是一個追加的兩倍。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.