今天PROD遇到問題了,查詢大量數據,而後返回XML, 在StringBuilder.append時發生錯誤,並且發生錯誤是在append一個小String時發生的錯誤。若是內存設置也很大,而且出示capacity的邏輯也比較麻煩,那麼就要從設計上下功夫了,好比看看爲何在這一短期訪問量這麼大,能不能均衡一下。String在expandCapacity會進行一下currentsize*2 + 2,是否大於要追加的string的長度,若是小於就擴展當前長度+要追加的String的長度。 java
ArrayList使用currentsize*3/2 + 1和追加的數據長度來比較 app
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2882)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:390)
at java.lang.StringBuilder.append(StringBuilder.java:119) post
A: ui
http://www.captaincasademo.com/forum/posts/list/1503.page this
Hi,
today we were forced to dive into the StringBuffer class - after looking into a OutOfMemory problem in our client.
It's "amazing" that the following code causes an OutOfMemory - event though the virtual machine is started with -Xmx256m:
Code: spa
public static void main(String[] args) { try { char[] chars = new char[30000000]; for (int i=0; i<chars.length; i++) chars[i] = 'A'; String s = new String(chars); StringBuffer sb = new StringBuffer(); System.out.println("Now appending s"); sb.append(s); System.out.println("Now appending Hallo"); sb.append("Hallo!"); // ---- System.out.println("Finished!"); } catch (Throwable t) { t.printStackTrace(); } } OUTPUT: Now appending s Now appending Hallo java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2882) at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:390) at java.lang.StringBuffer.append(StringBuffer.java:224) at org.eclnt.client.ztest.TestMem.main(TestMem.java:22)
public static String concatenateStrings(List<String> items) { if (items == null) return null; if (items.size() == 0) return ""; int expectedSize = 0; for (String item: items) expectedSize += item.length(); StringBuffer result = new StringBuffer(expectedSize); for (String item: items) result.append(item); return result.toString(); }
public static void main(String[] args) { try { char[] chars = new char[30000000]; for (int i=0; i<chars.length; i++) chars[i] = 'A'; String s = new String(chars); List<String> buffer = new ArrayList<String>(); System.out.println("Now appending s"); buffer.add(s); System.out.println("Now appending Hallo"); buffer.add("Hallo!"); String all = concatenateStrings(buffer); // ---- System.out.println("Finished!"); } catch (Throwable t) { t.printStackTrace(); }
you can set an inital capacity for StringBuffer i guess.
Also i would recommend to use StringBuilder instead of StringBuffer (in case you don't need a garanteed synchronisation).
this test (link) resulted in a 34% better perfomance for StringBuilder. 設計
http://littletutorials.com/2008/07/16/stringbuffer-vs-stringbuilder-performance-comparison/ code
Hi,
you are 100% right...!
The setting of an internal capacity is by the way the "trick" behind the concatenateStrings-method int the text above. Before appending things in the StringBuffer, its size is calculated (variable "expectedSize").
Regards, Björn orm