StringBuilder中的奇怪OutOfMemoryError setLength(0)

时间:2014-03-26 09:50:57

标签: java android out-of-memory stringbuilder

似乎没有人报告类似情况......我完全不知道发生了什么......

我有一个大小为8Mb的StringBuilder来处理大型String result。我正在尝试重用StringBuilder。我认为设置长度= 0只会重置计数器而不分配新内存?

try {
      //result.length() around 4Mb
        StringBuilder sBuilder = new StringBuilder(result.length());
        result = DoSomethingToResult1(sBuilder, result); //shrink result a bit using replaceAll

        try {

            sssBuilder.setLength(0);
            result = DoSomethingToResult2(sBuilder, result); //shrink result further using replaceAll
        } catch (OutOfMemoryError e) {
             Log.d(TAG, "Out of Memory on 2");
        }

        try {
            sBuilder.setLength(0);  //OutOfMemory thrown here.          
            result = DoSomethingToResult3(sBuilder, result); //shrink result even further using replaceAll
        } catch (OutOfMemoryError e) {
             Log.d(TAG, "Out of Memory on 3");
        }

    } catch (OutOfMemoryError e) {
                Log.d(TAG, "Cannot create sBuilder");
    }

该过程通常会在第二个setLength(0)上消失,有时会在第一个setLength(0)上消失,但它始终可以在开头创建sBuilder

DoSomethingToResult中,我将result拆分为100Kb大小的块并逐个追加sBuilder,返回sBuilder.toString()。所以问题不是来自replaceAll。由于它通过了​​第一个过程,我认为toString()也不是问题所在。

我试过了:

sBuilder.setLength(0);
System.gc();
try{
    Thread.sleep(1000);
}catch(Exception e){};

System.gc();
try{
    Thread.sleep(1000);
}catch(Exception e){};
sBuilder.setLength(0);

都失败了。

日志输出:

E/dalvikvm-heap(27130): Out of memory on a 8723792-byte allocation.
I/dalvikvm(27130): "AsyncTask #1" prio=5 tid=11 RUNNABLE
I/dalvikvm(27130):   | group="main" sCount=0 dsCount=0 obj=0x42036a18 self=0x51c2eb08
I/dalvikvm(27130):   | sysTid=27151 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=1371731208
I/dalvikvm(27130):   | schedstat=( 0 0 0 ) utm=197 stm=17 core=1
I/dalvikvm(27130):   at java.lang.AbstractStringBuilder.setLength(AbstractStringBuilder.java:~567)
I/dalvikvm(27130):   at java.lang.StringBuilder.setLength(StringBuilder.java:44)

1 个答案:

答案 0 :(得分:0)

将长度设置为0不会自动调用GC启动。您可以做的是循环并调用System.gc,然后等待一段时间直到可用内存增加。然后从循环中断开并继续下一个过程。

您也可以尝试分配新的构建器,而不是在每次迭代中清除缓冲区。

相关问题