2016-02-13 3 views
5

У меня есть простой класс для целей иллюстрации:Почему компилятор Java не оптимизирует тривиальный метод?

public class Test { 

    public int test1() { 
     int result = 100; 
     result = 200; 
     return result; 
    } 

    public int test2() { 
     return 200; 
    } 
} 

Байткод производится компилятором (проверяемого на javap -c Test.class) заключается в следующем:

public int test1(); 
Code: 
    0: bipush  100 
    2: istore_1 
    3: sipush  200 
    6: istore_1 
    7: iload_1 
    8: ireturn 

public int test2(); 
Code: 
    0: sipush  200 
    3: ireturn 

Почему компилятор не оптимизируя test1 метод для того же байт-кода, созданного для метода test2? Я ожидал бы, по крайней мере, избежать избыточной инициализации переменной result, учитывая, что легко сделать вывод, что значение 100 вообще не используется.

Я наблюдал это как с компилятором Eclipse, так и с javac. версия

javac: 1.8.0_72, устанавливается как часть JDK вместе с Java:

Java(TM) SE Runtime Environment (build 1.8.0_72-b15) 
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode) 
+6

* Спецификация языка Java * не требует таких оптимизаций, поэтому не имеет смысла говорить о «компиляторе», как если бы он был только одним. Вы должны указать, какой компилятор вы используете. – ruakh

+5

классический ответ: оптимизация выполняется в JVM (http://stackoverflow.com/questions/5981460/optimization-by-java-compiler) – wero

+0

@ruakh Хорошее замечание; добавлена ​​информация о компиляторе. –

ответ

4

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

Байт-код - это просто описание того, как должна себя вести ваша программа. Среда выполнения может использовать любую оптимизацию для вашего байтового кода.

Конечно, можно утверждать, что такие тривиальные оптимизации могут применяться даже во время компиляции, но в целом имеет смысл не распространять оптимизацию на несколько этапов. Любая оптимизация фактически вызывает нехватку информации об исходной программе, и это может сделать другие оптимизации невозможными. Это говорит о том, что не все «лучшие оптимизации» всегда очевидны. Легкий подход к этому - просто отказаться (почти) от всех оптимизаций во время компиляции и вместо этого применить их во время выполнения.

+0

yes - по крайней мере информация о номере линии будет потеряна, поэтому stacktrace не будет точным; и отладка будет сложнее. – ZhongYu

4

JVM оптимизирует байткод, создавая то, что называется код кэшем. В отличие от C++, JVM может собирать много данных о вашей программе, например, Насколько жарко это для цикла?, Этот блок кода даже стоит оптимизировать? и т. Д. Поэтому оптимизация здесь очень полезна и часто дает лучшие результаты.

Если оптимизировать при переводе с Java в байткод (то есть, когда вы звоните JAVAC), вашего код может быть оптимальным для вашего компьютера, но не для какой-то другой платформы. Поэтому нет смысла оптимизировать здесь.

В качестве примера, предположим, что ваша программа использует шифрование AES. Современные процессоры имеют набор инструкций на основе AES, со специальным оборудованием, чтобы шифрование проходило намного быстрее.

Если Javac пытается оптимизировать во время компиляции, то он будет либо

  • оптимизирует инструкции на программном уровне, в этом случае вы программируете обыкновение пользу от современных процессоров, или,
  • заменить ваши инструкции AES с эквивалентными инструкциями CPU-AES, поддерживаемые только на новых процессорах, что уменьшит вашу совместимость.

Если вместо Javac оставляет их как в byptcode, то JVM работает на новых процессорах может распознать их как AES и использовать эту способность процессора, в то время как JVMs работает на старых процессорах может оптимизировать их на уровне программного обеспечения во время выполнения (кеш кода), давая вам оптимальность и совместимость.

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