Спасибо, кэп. Именно байткод помог мне понять почему следующий код печатал 10 в jdk1.3:
{
int i=10;
}
{
int x;
println(x);
}
Именно тесты комманды работяющей над Lucene выявили на довольно подзней стадии серьезный баг в jdk7 перед самым релизом.
Ни один компилятор не развернет reversed loop, максимум закеширует array.length, т.е. пожертвует регистром ради производительности. Они, компиляторы, сейчас чертовски хороши, но их пока писали люди, а людям свойственно ошибаться. Давайте будем думать, а не идеализировать.
Ведь недалеко еще ушил те времена когда synchronized блок в однопоточной программе было страшное зло, где за вызов метода через интерфейс, а не конкретный класс (java.util.List vs java.util.ArrayList) били по рукам и т.п.
Было ведь?
та ладно. еще скажите что Вы белые и пушистые :)
Вы хорошие performance инженеры, Вам судьба велела цеплятся к мелочам, словам, незначительным деталям. Это бывает немного необычно, но как-то переживу.
Пример показывает что вынесение доступа к volatile переменной за скобки цикла дало прирост производителности. Хотя в обычной ситуации не дало бы ничего.
Есть две грани, с одной стороны можно писать код ради перформанса в ущерб функионалу, с другой стороны забить на все оптимизации и рекомендации. И то, и другое само по себе плохо, важно понимать где золотая середина, где надо знать что написание опреденного кода приведет к проблеме (например конкатенация строк в цикле), а где можно довериться оптимизатору и например не боятся виртуальных вызовов.
private volatile int[] array = new int[10000];
...
public void test(){
int s = 0;
for(int i=0; i<array.length; i++) {
s+=array[i];
}
sum = s;
}
Throughput = 62 ops/msec.
Жаль красным нельзя выделить как на слайде. И чего Вы на меня накинулись, кусок хлеба я у Вас не отбирал, дорогу Вам не переходил, может скучно было и решили срач в комментах развести, а тут еще и тема близкая по духу. Как-то глупо все вышло.
«Есть» и «работают с» это разные вещи, в байткоде есть инструкции, а стек есть у виртуальной машины. У байткода нет стека. А только инструкции для работы с ним + max_stack:
«The value of the max_stack item gives the maximum depth of the operand stack of this method (§2.6.2) at any point during execution of the method.»
Я не настаиваю, просто сказал что постфиксному надо на один регистр больше, что бы у вас там не было, Java, C++, C… И я не против того что это ерунда в сравнении с мировой революцией.
Вы реально к словам цепляетесь и делаете вид что про стек не надо думать никогда, его типа нет. Да, в 99% случаев не надо про него думать, а про разницу пост- и преинкремента и вовсе можно забыть, но раньше это было актуально.
Вы отрицаете очевидное, как будто я придумал reverse for loop. Да в Java такими глупостями не стоит заморачиваться, ну разве что Вам действительно надо пройтись по массиву в обратном порядке. Повторюсь, слово «оптимизация» в кавычках кавычках кавычках кавычках кавычках.
Не надо мне доказывать что оптимизации зло, я сам могу рассказать про
— make it work
— make it rihgt
— make it fast.
Я Вас ни в чем не обвинял, просто сказал что у меня такое ощущение возникло.
И Вы меня простите конечно, но что и где именно я посоветовал что «вот так надо делать, а не то Ваше Java приложение сожрет все доступные ресурсы»?
1. По поводу пре- и постинкремента Вы согласитесь что раньше раньше раньше раньше на это замарачивались в цикле for из-за лишнего регистра?
2. Про сравнение с 1000, а не с нулем. Слово «оптимизация» в кавычках кавычках кавычках кавычках? А если по сути то что проще, загрузить 2 числа на стек и их сравнить или загрузить одно для сравнения? Точно издеваетесь, а жаль.
Читаем еще раз:
> Ну разве что по старинке все привылки писать ++counter, а не counter++.
Ключевое слово по старинке. Раньше это было важно потому что постинкремент требует +1 регистр.
Представьте себе рекурсивный вызов, и в теле функции Вы наплевательски отнеслись к стеку. Это может закончится выходом за стек. Не думайте что StackOverflowError это только когда баг в рекурсии. Стек очень часто урезают на серверах для экономии памяти. (по умолчанию на стек дается 1MB, т.е. на тысячу потоков это 1GB).
Вы может считает что ошибки делать нельзя, а я считаю что когда ты новичок ты только это и должен делать что ошибаться, ошибаться и еще раз ошибаться. А иначе никак.
Стек вызовов. Вы вроде бы не новичок, неужели действительно не знаете почему преинкремент предпочтительнее постинкремента?
Я не говорю про performance, он тут одинаковый.
Потому что если вы вызываете varargs метод в цикле и каждый раз при этом создается пустой массив, пусть и быстро создается, но все его назначение лишь в том чтобы бы съеденым GC, то лучше избежать этого.
void method(String... args) {
// do something
}
void user() {
for(int count=0; counter<1000; counter++) method(); // this is slow
for(int count=1000; counter-->0;) method((String[])null)// this is fast
}
Именно тесты комманды работяющей над Lucene выявили на довольно подзней стадии серьезный баг в jdk7 перед самым релизом.
Ни один компилятор не развернет reversed loop, максимум закеширует array.length, т.е. пожертвует регистром ради производительности. Они, компиляторы, сейчас чертовски хороши, но их пока писали люди, а людям свойственно ошибаться. Давайте будем думать, а не идеализировать.
Было ведь?
Про пример ответил выше.
Вы хорошие performance инженеры, Вам судьба велела цеплятся к мелочам, словам, незначительным деталям. Это бывает немного необычно, но как-то переживу.
Пример показывает что вынесение доступа к volatile переменной за скобки цикла дало прирост производителности. Хотя в обычной ситуации не дало бы ничего.
Есть две грани, с одной стороны можно писать код ради перформанса в ущерб функионалу, с другой стороны забить на все оптимизации и рекомендации. И то, и другое само по себе плохо, важно понимать где золотая середина, где надо знать что написание опреденного кода приведет к проблеме (например конкатенация строк в цикле), а где можно довериться оптимизатору и например не боятся виртуальных вызовов.
Все, можно
ржатьконструктивно критиковать.Жаль красным нельзя выделить как на слайде. И чего Вы на меня накинулись, кусок хлеба я у Вас не отбирал, дорогу Вам не переходил, может скучно было и решили срач в комментах развести, а тут еще и тема близкая по духу. Как-то глупо все вышло.
— make it right
постораюсь больше их не путать.
«The value of the max_stack item gives the maximum depth of the operand stack of this method (§2.6.2) at any point during execution of the method.»
Вы отрицаете очевидное, как будто я придумал reverse for loop. Да в Java такими глупостями не стоит заморачиваться, ну разве что Вам действительно надо пройтись по массиву в обратном порядке. Повторюсь, слово «оптимизация» в кавычках кавычках кавычках кавычках кавычках.
Не надо мне доказывать что оптимизации зло, я сам могу рассказать про
— make it work
— make it rihgt
— make it fast.
И Вы меня простите конечно, но что и где именно я посоветовал что «вот так надо делать, а не то Ваше Java приложение сожрет все доступные ресурсы»?
1. По поводу пре- и постинкремента Вы согласитесь что раньше раньше раньше раньше на это замарачивались в цикле for из-за лишнего регистра?
2. Про сравнение с 1000, а не с нулем. Слово «оптимизация» в кавычках кавычках кавычках кавычках? А если по сути то что проще, загрузить 2 числа на стек и их сравнить или загрузить одно для сравнения? Точно издеваетесь, а жаль.
тут используется постинкремент и неявное создание пустого массива
тут используется еще одна «оптимизация», сравнение с нулем быстрее чем с 1000. И не создается лишний мусор.
Ощущение что я от тролей отбиваюсь :(
> Ну разве что по старинке все привылки писать ++counter, а не counter++.
Ключевое слово по старинке. Раньше это было важно потому что постинкремент требует +1 регистр.
Представьте себе рекурсивный вызов, и в теле функции Вы наплевательски отнеслись к стеку. Это может закончится выходом за стек. Не думайте что StackOverflowError это только когда баг в рекурсии. Стек очень часто урезают на серверах для экономии памяти. (по умолчанию на стек дается 1MB, т.е. на тысячу потоков это 1GB).
P.S. Кстати в байткоде нет стека, там есть только max_stack: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.3
Я не говорю про performance, он тут одинаковый.