高效循环避免多个垃圾收集Android的呼叫

时间:2012-01-05 15:21:02

标签: java android for-loop garbage-collection

我有一个Android应用程序,允许用户记录数据(如加速度计,纬度,经度等)。这些字段共有9个,用户最多可记录10分钟(每个字段3000个记录)。因此,可以收集总共27,000个数据点。用户还可以拍摄照片和视频以上传SD卡。

当用户完成数据收集(或10分钟后)时,数据存储在String中,后来作为.csv文件上传到SD卡。问题是,由于大量的垃圾收集(它似乎每秒大约收集5个左右,因此需要永远才能将数据追加到字符串中。)附加开始快速,但随着数据的增加,似乎越来越慢。

这是导致延迟的循环:

           for( i = 0 ; i < len2 ; i++ ) {
                data += accelX[i] + ", " + accelY[i] + ", " + accelZ[i] + 
                ", " + accelT[i] + ", " + latitu[i] + ", " + 
                longit[i] + ", " + orient[i] + ", " + 
                magneX[i] + ", " + magneY[i] + ", " + magneZ[i] + 
                ", " + millis[i] + "\n";

                partialProg = 100.0 * ( (double)(i+1) / (double)(len2));
                dia.setProgress((int) partialProg);

            }

data只是一个字符串,没有任何东西被new编辑,所以我不确定为什么经常调用GC。我的问题是:这里有什么问题,和/或我怎样才能提高效率呢?

4 个答案:

答案 0 :(得分:3)

您正在创建许多对象。每次使用operator+时,实际上都会创建一个新对象,如果你重复很多次,那就是广阔的对象。

您可以使用StringBuilderappend来提高效率,并在完成后创建字符串。

例如:

sb.append(accelX[i]).append(',').append(accelY[i]).append(',').append(accelZ[i]);

[其中sb是StringBuilder的一个实例]

答案 1 :(得分:1)

您可能会做的一项改进是StringBuffer来构造数据,这样您就可以避免String构造和连接操作。例如:

StringBuffer buff = new StringBuffer();
buff.append(accelX[i]).append(...).apend(...)

答案 2 :(得分:1)

您可以使用StringBuilder来连接数据:

StringBuilder sb = new StringBuilder();
for( i = 0 ; i < len2 ; i++ ) {
    sb.append(accelX[i]).append(", ");
    sb.append(accelY[i]).append(", ");
    sb.append(accelZ[i]).append(", ");
    sb.append(accelT[i]).append(", ");
    sb.append(latitu[i]).append(", ");
    sb.append(longit[i]).append(", ");
    sb.append(orient[i]).append(", ");
    sb.append(magneX[i]).append(", ");
    sb.append(magneY[i]).append(", ");
    sb.append(magneZ[i]).append(", ");
    sb.append(millis[i]).append("\n");
}

StringBuilder是inherently faster,用于构建长字符串。

它还避免了将如此多的String对象分配到堆中;因为每个+ =运算符都在创建一个新的String对象,而不是修改最后一个。这反过来会导致大量的GC调用来清理所有冗余的String对象。另见:http://chaoticjava.com/posts/stringbuilder-vs-string/

正如马塞洛指出的那样;您可能还发现在内存中处理大量数据可能会在低规格的Android设备上出现问题,此时您应该考虑每X次迭代将StringBuilder的内容附加到临时文件中以保持较低的占用空间。在流程结束时,您可以将文件流式传输到计划的目标位置,或者根据需要将其段读回内存。

答案 3 :(得分:1)

字符串上的

+运算符实际上使用StringBuilder,因此每个循环执行至少两次分配(新StringBuilder然后StringBuilder在{{1}时创建一个字符串调用它来将结果分配给.toString())。 解决此问题的最佳方法是在循环前创建data

StringBuilder