Эффективный цикл, чтобы избежать множественных вызовов для сбора мусора для Android - PullRequest
2 голосов
/ 05 января 2012

У меня есть приложение для Android, которое позволяет пользователю записывать данные (такие как акселерометр, широта, долгота и т. Д.). Всего имеется 9 таких полей, и пользователь может записывать до 10 минут (3000 записей на поле). Таким образом, можно собрать 27 000 точек данных. Пользователь также может делать фотографии и видео для загрузки SD-карты.

Когда пользователь завершает сбор данных (или истекают 10 минут), данные сохраняются в строке, которая затем загружается на карту SD в виде файла .csv. Проблема, однако, в том, что для добавления данных в строку требуется навсегда из-за огромного количества мусора (кажется, что это приблизительно 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 ]

3 голосов
/ 05 января 2012

Вы создаете много объектов. каждый раз, когда вы используете operator+, вы фактически создаете новый объект, который является обширным [если вы повторяете это много раз]

Вы можете сделать его более эффективным, используя StringBuilder и , добавьте к нему и создайте строку, когда закончите.

например:

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

[где sb - это экземпляр StringBuilder]

1 голос
/ 05 января 2012
Оператор

+ для строк на самом деле использует StringBuilder, таким образом, вы выполняете как минимум два выделения для цикла (новый StringBuilder, а затем StringBuilder создает строку, когда .toString() вызывается для нее, чтобы присвоить результат до data). Лучший способ решить эту проблему - создать StringBuilder перед циклом.

StringBuilder buf = new StringBuilder();
String sep = ", ";
for( i = 0 ; i < len2 ; i++ ) {
    buf.append(accelX[i]).append(sep).append(accelY[i]).append(sep);
    buf.append(accelZ[i]).append(sep).append(accelT[i]).append(sep);
    buf.append(latitu[i]).append(sep).append(longit[i]).append(sep);
    buf.append(magneX[i]).append(sep).append(magneY[i]).append(sep);
    buf.append(magneZ[i]).append(sep).append(millis[i]).append('\n');
    partialProg = 100.0 * ( (double)(i+1) / (double)(len2));
    dia.setProgress((int) partialProg);
}
1 голос
/ 05 января 2012

Вы можете использовать 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 по своей природе быстрее для построения длинных строк.

Это также позволяет избежать размещения большого количества объектов String в куче;поскольку каждый оператор + = создает новый объект String, а не модифицирует последний.Это, в свою очередь, приводит к большому количеству вызовов GC для очистки всех избыточных объектов String.Смотрите также: http://chaoticjava.com/posts/stringbuilder-vs-string/

Как отмечает Марсело;Вы также можете обнаружить, что работа с большими объемами данных в памяти может стать проблемой на устройствах Android с низкой спецификацией, и в этот момент вам следует рассмотреть возможность добавления содержимого вашего StringBuilder во временный файл каждые X итераций, чтобы сохранить низкую площадь.В конце процесса вы можете передать файл туда, где запланировано место назначения, или прочитать его сегменты обратно в память по требованию.

1 голос
/ 05 января 2012

Одним из улучшений, которое вы можете сделать, является StringBuffer для построения данных, таким образом, вы не сможете избежать операций создания и объединения строк. Например:

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