2014-10-17 2 views
7

Рассмотрим следующий фрагмент кода Java:Будет ли компилятор Java оптимизировать String.length() в состоянии for-loop?

String buffer = "..."; 
for (int i = 0; i < buffer.length(); i++) 
{ 
    System.out.println(buffer.charAt(i)); 
} 

Поскольку String является непреложным и buffer не переназначен в цикле, будет компилятор Java должен быть достаточно умны, чтобы оптимизировать прочь buffer.length() вызов в для условия цикла в? Например, испустит ли он байт-код, эквивалентный следующему, где buffer.length() назначается переменной, и эта переменная используется в условии цикла? Я читал, что некоторые языки, такие как C#, делают этот тип оптимизации.

String buffer = "..."; 
int length = buffer.length(); 
for (int i = 0; i < length; i++) 
{ 
    System.out.println(buffer.charAt(i)); 
} 

ответ

6

В Java (и в .NET), длина строки подсчитывают (число точек в UTF-16 кода), так что найти длину является простой операцией.

Компилятор (javac) может или не может выполнить hoisting, но JVM JIT компилятор almost certainly вставит вызов к .length(), не делая buffer.length() ничего больше, чем доступ к памяти.

+0

Что относительно действительно длинных строк, скажем, несколько 1000K? – Drejc

+0

Что такое «дрожь»? – stackoverflowuser2010

+0

Это 'O (1)' стоимость, так что это не имеет значения.Строка хранится как '{length = 1000, character data = {0x65, ... 0x65}}'. – Mitch

1

Компилятор Java (javac) не выполняет такую ​​оптимизацию. Компилятор JIT, скорее всего, включит метод length(), который, по крайней мере, позволит избежать накладных расходов на вызов метода.

В зависимости от JDK вы работаете, то length() метод сам по себе, вероятно, возвращает конечный length поле, которое дешевый доступ к памяти, или длина внутреннего массива char[] струны. В последнем случае длина массива постоянна, а ссылка на массив предположительно равна final, поэтому JIT может быть достаточно сложной, чтобы записывать длину один раз во временное, как вы предлагаете. Однако подобная вещь представляет собой деталь реализации. Если вы не будете контролировать каждую машину, на которой будет работать ваш код, вы не должны делать слишком много предположений о том, какой JVM он будет запускать или какие оптимизации он будет выполнять.

Что касается того, как вы должны писать свой код, вызов length() непосредственно в условии цикла является общей схемой кода и дает возможность читать. Я бы все упростил, и пусть оптимизатор JIT выполнит свою работу, если вы не находитесь в критическом кодовом пути, который продемонстрировал проблемы с производительностью, и вы также продемонстрировали, что такая микро-оптимизация стоит того.

+0

«JIT-компилятор, скорее всего, построит метод length()». Любая документация по этому поводу? Мне нравится читать об этом. – stackoverflowuser2010

+1

На самом деле он не возвращает длину символа 'char []', так как 'String' может использовать только часть его. 'String' имеют собственное поле 'final int', чтобы запомнить длину. – resueman

+0

По умолчанию, я считаю, что JVM Oracle будет встроить до 35 ** байтов ** байт-кода для метода, который был вызван хотя бы один раз. Я считаю, что существует более высокий порог для часто называемых методов. Вы можете проверить [этот вопрос в StackOverflow] (http://stackoverflow.com/questions/18737774/hotspot-jit-inlining-strategy-top-down-or-down-top). @resueman, версия источника, на который я смотрю, не имеет отдельного поля. Еще один пример предположений, которые мы не должны делать о JVM/JDK клиентского компьютера :). –

1

Вы можете сделать несколько вещей, чтобы изучить два варианта вашей реализации.

  1. (сложность: простая) Проведите тест и измерьте скорость в аналогичных условиях для каждой версии кода. Убедитесь, что петля достаточно значительна, чтобы заметить разницу, возможно, ее нет.

  2. (трудность: средняя) Изучите байт-код с помощью javap и посмотрите, как компилятор интерпретировал обе версии (это может различаться в зависимости от реализации javac), или это может быть не так (когда поведение было указано в спецификации и не осталось места для интерпретации разработчиком).

  3. (трудность: жесткий). Изучите вывод JIT обеих версий с помощью JITWatch, вам нужно будет очень хорошо понимать байт-код и ассемблер.

Смежные вопросы