簡體   English   中英

如何使用字符串有效地管理內存?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM