简体   繁体   English

StringBuilder setLength(0)处出现奇怪的OutOfMemoryError

[英]Strange OutOfMemoryError at StringBuilder setLength(0)

It seems no one has reported similar situations... I have absolutely no idea what happened... 似乎没有人报告过类似情况...我完全不知道发生了什么...

I have a StringBuilder of size 8Mb to process a large String result . 我有一个大小为8Mb的StringBuilder来处理较大的String result I am trying to reuse the StringBuilder . 我正在尝试重用StringBuilder I thought setting length = 0 will just reset the counter and not allocate new memory? 我认为将length设置为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");
    }

The process usually dies on the second setLength(0) , sometimes dies on the first setLength(0) , but it can always create the sBuilder in the beginning. 该进程通常死在第二个setLength(0) ,有时死在第一个setLength(0) ,但是它总是可以在开始时创建sBuilder

In DoSomethingToResult , I split result into chunk of 100Kb size and append to sBuilder one by one, returning sBuilder.toString(). DoSomethingToResult ,我将result分成100Kb大小的块,并一一追加到sBuilder ,返回sBuilder.toString()。 So problem does not come from replaceAll . 因此问题不是来自replaceAll And since it passed the first process, I don't think the toString() is the problem either. 而且由于它通过了​​第一个过程,所以我也不认为toString()就是问题。

I tried: 我试过了:

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

or 要么

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

Both failed. 都失败了。

Log output: 日志输出:

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)

Setting length to 0 doesn't automatically invoke the GC to kick in. What you can do is have a loop and call System.gc, then wait for a while until available memory increases. 将length设置为0不会自动调用GC来启动。您可以做的是循环并调用System.gc,然后等待一段时间,直到可用内存增加。 Then break from the loop and continue with your next process. 然后退出循环,继续进行下一个过程。

You can also try allocating a new builder rather than clearing the buffer in each iteration. 您也可以尝试分配新的构建器,而不是在每次迭代中清除缓冲区。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM