StringBuffer is dangerous when dealing with lonnnng Strings!!!
来源:互联网 发布:tomcat下js文件未生效 编辑:程序博客网 时间:2024/05/18 01:07
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:
A String with the length of 30.000.000 characters is added to a stringbuffer - that's it. It's even more astonishing that the error is NOT thrown when appending the "big" string, but when appending "Hallo".
The reason is the internal processing of StirngBuffer. StringBuffer keeps everyhing in an char-array, and there is a certain method that increases the char-array-size when finding out that the array does not fit anymore. The method increases the size by at least "2 * currentSize + 2". This may make sense for small sizes, but it's completely a wrong decision for big sizes. In our case the appending of "Hello" means that the total array size is increased by 60.000.002 as minimum, so that the minimum size is 90.000.002 afterwards. And now, the previous char array with length of 30.000.000 needs to be copied into the one of 90.000.002 - this means both arrays co-exist for a short duration of time, resulting in 120.000.002 characters being in memory (and of course there is some additional memory blocked by the array object). So the appending of "Hallo" means a lot... - enough to cause out of memory.
When concatenating long strings, then it is as consequence essential to carefully work with StringBuffers. We eliminated our OutOfMemory problems by using the following utitlity method:
Code:
When now changing the test code to:
Code:
It's "amazing" that the following code causes an OutOfMemory - event though the virtual machine is started with -Xmx256m:
Code:
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)
A String with the length of 30.000.000 characters is added to a stringbuffer - that's it. It's even more astonishing that the error is NOT thrown when appending the "big" string, but when appending "Hallo".
The reason is the internal processing of StirngBuffer. StringBuffer keeps everyhing in an char-array, and there is a certain method that increases the char-array-size when finding out that the array does not fit anymore. The method increases the size by at least "2 * currentSize + 2". This may make sense for small sizes, but it's completely a wrong decision for big sizes. In our case the appending of "Hello" means that the total array size is increased by 60.000.002 as minimum, so that the minimum size is 90.000.002 afterwards. And now, the previous char array with length of 30.000.000 needs to be copied into the one of 90.000.002 - this means both arrays co-exist for a short duration of time, resulting in 120.000.002 characters being in memory (and of course there is some additional memory blocked by the array object). So the appending of "Hallo" means a lot... - enough to cause out of memory.
When concatenating long strings, then it is as consequence essential to carefully work with StringBuffers. We eliminated our OutOfMemory problems by using the following utitlity method:
Code:
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(); }
When now changing the test code to:
Code:
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(); }
0 0
- StringBuffer is dangerous when dealing with lonnnng Strings!!!
- 一些记录 when dealing with MP4 container
- problem with IBM JVM when dealing with xslt function format-number()
- Dealing with rollback segment corruption when you encounter Error encountered while recovering trans
- Dealing with Adversity
- unsigned type is dangerous
- 试译“Time is dangerous”
- Dealing with WMI Timeouts (c#)
- XSLT(8) Dealing with namespace
- Dealing with Audio Output Hardware
- TSQL : Compare variable with integer when variable is nothing
- onStartCommand after service process is killed when started with START_STICKY
- CurrencyManager Collection - Dealing with SuspendBinding and ResumeBinding
- Dealing with C++ "Unused Parameter" Warnings
- C# Tutorial - Dealing With Unhandled Exceptions
- Dealing with bitmap object in android NDK
- 英语练习140 Dealing with exams
- Files and Exceptions: Dealing with Errors
- Python装饰器有趣实例探究
- c# C(m,n) 排列组合算法
- 【算法】快速排序法:Quicksort
- 平衡二叉排序树的各种算法
- Win7设置outlook2013开机自启动
- StringBuffer is dangerous when dealing with lonnnng Strings!!!
- Linux 环境下开发 常用指令
- 一、文件安全与权限
- 内存分布
- static与继承
- error LNK2005: __errno already defined in MSVCRTD.lib(MSVCR90D.dll)
- 反射 C#
- 串及其功能的实现
- Java-调试技巧(一)