我有一个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。我的问题是:这里有什么问题,和/或我怎样才能提高效率呢?
答案 0 :(得分:3)
您正在创建许多对象。每次使用operator+
时,实际上都会创建一个新对象,如果你重复很多次,那就是广阔的对象。
您可以使用StringBuilder和append来提高效率,并在完成后创建字符串。
例如:
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