[英]How to efficiently manage memory using Strings?
考慮一段示例代碼。
public void testString()
{
int i = 0;
while(i < 100000000)
{
String s ="Hi hello bye" +i;
i++;
}
}
在每次迭代中,都會創建一個新的String,並且下一次迭代不再需要它的值。 我嘗試打印之前消耗的內存並發布此testString()功能。 這是他們的價值觀。
Before invoking testString():
Total Memory: 91684864 (87.4375 MB)
Max Memory: 1360855040 (1297.8125 MB)
Free Memory: 72163552 (68.82052612304688 MB)
After invoking testString():
Total Memory: 424280064 (404.625 MB)
Max Memory: 1360855040 (1297.8125 MB)
Free Memory: 171766816 (163.80960083007812 MB).
我看到使用了大量內存,並且由於當前處理字符串的方式,我擔心JVM堆可能會超出范圍。 在迭代2中不再需要為迭代1生成的字符串,並且可以釋放其存儲空間。 我相信這不會發生在這里。
我嘗試使用StringBuffer和StringBuilder對象,內存使用情況似乎有很小的改善。
請幫助我更好,更好的方法。
在迭代2中不再需要為迭代1生成的字符串,並且可以釋放其存儲空間。 我相信這不會發生在這里。
它肯定正在發生。
你創造了1億個字符串,每個字符串至少有13個字符 - 其中大部分都是大約20個字符。 每個字符串由一個對象(有開銷)和一個char[]
- 所以我猜它占用大約60個字節的20個字符的字符串。
如果垃圾收集無效,那么每個需要60個字節的1億個對象需要6GB - 而你看到的總內存只比開始時大約300MB。
該字符串正在收集-只是沒有馬上 。
您還沒有告訴我們您需要對實際代碼中的字符串做什么(我假設有一個真正的動機) - 假設您在循環的每次迭代中實際上需要一個字符串,我不認為使用StringBuilder
會幫助你。 如果你只需要數據是一個StringBuilder
那么你可以使它更有效率,但很少你創建一個StringBuilder
但不要在其上調用toString
。
第一次運行會發生什么
JVM運行代碼,生成字符串,並在一定的時間間隔內垃圾收集器釋放已用內存。 除了一些浪費的執行時間,程序將正常運行。
如果頻繁調用該函數會發生什么
JVM將開始優化循環,意識到沒有對這些字符串做任何事情,並將整個函數標記為死代碼。 最終調用該函數幾乎沒有任何作用,因為JVM將內容轉換為簡單的return
請幫助我更好,更好的方法。
因為即使是JVM也不知道你的代碼應該做什么......你想做什么? 對於您手頭的實際問題,可能有最佳解決方案,這與您最初發布的代碼示例非常不同。
這取決於你如何使用StringBuilder。 這個
StringBuilder sb = new StringBuilder("");
while (i < 100000000) {
sb.delete(0, sb.length());
sb.append("Hi hello bye").append(i);
i++;
}
在內存消耗和速度方面都會更有效率
字符串是不可變的,當你要連續添加一個字符串時,它會為每次迭代創建一個字符串對象,因此內存已超出。 如果你使用StringBuilder,它在單個對象中工作,即使它處理多個迭代也會發生。 StringBuilder是可變的。
StringBuilder iter = new StringBuilder("");
while (i < 100000000)
{
iter.delete(0, iter.length());
iter.append("Hi hello bye").append(i);
i++;
}
JVM永遠不會從未引用的對象(例如示例程序中的字符串)中耗盡堆內存,因為在它拋出OutOfMemory
異常之前,它將運行垃圾收集。 請參閱Java虛擬機規范第6.3節中的此異常的語義:
OutOfMemoryError:Java虛擬機實現已用完虛擬或物理內存,並且自動存儲管理器無法回收足夠的內存來滿足對象創建請求。
使用字符串構建器是您的最佳選擇。 由於您所需的字符串/字符串構建器數量巨大,因此您無法期望JVM在任何情況下都可以避免使用大量內存。 參考上面的統計數據:
使用字符串:總內存的可用內存40.48% ((163.80960083007812 MB/404.625 MB )*100)
為40.48% ((163.80960083007812 MB/404.625 MB )*100)
。
使用字符串構建器:總內存的可用內存69.35 % ((252.659 MB/364.3125 MB)*100)
為69.35 % ((252.659 MB/364.3125 MB)*100)
,這是一個非常顯着的改進。 此外,上述變量的使用僅在循環范圍內,因此JVM的垃圾收集器將在需要時運行以清除內存。
由於變量的范圍僅適用於while循環的迭代,因此在這里您不必擔心內存溢出,因為在下一次垃圾收集器執行時它將釋放所有內存:
while(i < 100000000)
{
String s ="Hi hello bye" +i;
i++;
}// no more required the s afterward
在每次迭代中,String將創建一個新對象,但現在不需要前一個,所以它在內存中,直到垃圾收集器清理它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.