Почему это строка андроида.формат собаки медленный?
Я реализовывал действие ListView с пользовательскими рисованными представлениями и имел следующий код:
@Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
....
canvas.drawText(String.format("%02d: %dx%d", position, w, h),
10, 15, cached_paint);
}
Почти ничего другого в методе onDraw, так что это сводило меня с ума, почему прокрутка была настолько плохой. Случайно я изменил параметр drawText, чтобы не использовать строку.формат и вдруг прокрутка снова стала масляным шелком. На самом деле, следующее Практически то же самое, но работает хорошо:
canvas.drawText("" + position + ": " + w + "x" + h,
10, 15, cached_paint);
Я ошеломлен. Почему последнее быстрее, чем вызов строки.формат? Я можно было бы ожидать, что конкатенация объектов создаст больше промежуточных объектов и в целом улучшит производительность, но я обнаружил прямо противоположное. На самом деле, когда работает со строкой.формат я получал много сообщений о выделении/освобождении от виртуальной машины.
Так почему же строка?формат настолько медленный, когда он, по-видимому, может быть быстрее (по крайней мере, когда он приходит из других языков программирования, где создание объектов дорого)?
3 ответа:
Конкатенация строк с
+
не создает много промежуточных объектов; в основном это StringBuffer и его внутренний символьный массив (который может быть перераспределен, если у него закончится емкость). О, и Струна, когда она соединяется.Также, с помощью
+
, большая часть работы по анализу типов данных объектов, входящих в строку, выполняется во время компиляции. с шнуром.форматирование, которое выполняется во время выполнения. В довершение всего, каждый примитивный тип, который вы передаете в String.формат должен быть автобоксинг, который генерирует намного больше объектов.
Я ошеломлен.Почему?
Почему последнее быстрее, чем вызов строки.формат?
Потому что она написана на Java.
%02d: %dx%d
- это не Java. Это должно быть проанализировано каждый раз, и правила выполняются каждый раз. Эти правила выполняются в Java, черезjava.util.Formatter
.Теперь
String.format()
можно было бы оптимизировать, заменив его реализацией собственного кода (C/C++), но я думаю, что varargs и JNI становятся грязными.Я бы ожидал, что объект конкатенация генерирует больше промежуточных объектов и в целом ухудшает производительность, но я обнаружил прямо противоположное. На самом деле, когда работает со строкой.формат я получал много сообщений о выделении/освобождении от виртуальной машины.
Это было бы потому, что
String.format()
довольно сложен и реализован в Java.
Чтобы получить максимальную производительность, вы можете создать форматер из пакета
java.text
и кэшировать его.final static DecimalFormat myFormat = new DecimalFormat("###"); @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); .... canvas.drawText(myFormat.format(w) + "x" + myFormat(h)); }
Для еще большей производительности можно использовать более быструю конкатенацию строк. Но это другой вид оптимизации, и не по теме для этого вопроса.