JIT-компилятор оптимизирует не круто, а очень круто

    Недавно Лукас Эдер заинтересовался в своём блоге, способен ли JIT-компилятор Java оптимизировать такой код, чтобы убрать ненужный обход списка из одного элемента:


    // ... а тут мы "знаем", что список содержит только одно значение
    for (Object object : Collections.singletonList("abc")) {
        doSomethingWith(object);
    }

    Вот мой ответ: JIT может даже больше. Мы будем говорить про HotSpot JVM 64 bit восьмой версии. Давайте рассмотрим вот такой простой метод, который считает суммарную длину строк из переданного списка:


    static int testIterator(List<String> list) {
        int sum = 0;
        for (String s : list) {
            sum += s.length();
        }
        return sum;
    }

    Многим Java-программистам известно, что этот код полностью эквивалентен следующему:


    static int testIterator(List<String> list) {
        int sum = 0;
        Iterator<String> it = list.iterator();
        while(it.hasNext()) {
            String s = it.next();
            sum += s.length();
        }
        return sum;
    }

    Разумеется, в общем случае в list может оказаться всё что угодно и поэтому JIT-компилятору придётся сгенерировать честные виртуальные вызовы на месте iterator(), hasNext() и next(), что, конечно, не очень быстро. Но что случится, если мы всегда будем вызывать этот метод, подавая ему на вход singletonList? Давайте добавим простенький метод main():


    public class Test {
        static int res = 0;
    
        public static void main(String[] args) {
            for (int i = 0; i < 100000; i++) {
                res += testIterator(Collections.singletonList("x"));
            }
            System.out.println(res);
        }
    }

    Здесь мы вызываем наш testIterator в цикле достаточное количество раз, чтобы скомпилировать метод JIT-компилятором C2. Как некоторые из вас уже знают, в виртуальной машине HotSpot есть два JIT-компилятора: C1 (клиентский) и C2 (серверный). В 64-битной версии Java 8 с настройками по умолчанию они работают совместно. Сперва метод компилируется с помощью C1 (который компилирует быстро, но создаёт не очень оптимальный код). При этом в код добавляются дополнительные инструкции, которые собирают некоторую статистику (это называется "профилирование"). Это, конечно, замедляет выполнение, но пригождается в дальнейшем. Среди различных профилей собирается профиль типов. В нашем случае JVM внимательно следит, какой тип имеет параметр list при каждом вызове. И тут виртуальная машина замечает, что в 100% случаев на входе был список типа Collections$SingletonList (который возвращает метод singletonList).


    Когда количество вызовов метода достигает некоторого порога, метод перекомпилируется компилятором C2, которому доступен собранный профиль. C2 делает разумное предположение, что раз до сих пор всегда был SingletonList, то и далее он будет часто попадаться. А значит, iterator() точно вызовет метод singletonIterator(). Но там уже нетривиальный объект, который, к примеру, содержит поле hasNext, чтобы отследить, что его не вызвали дважды, и кинуть если надо NoSuchElementException. Способен ли C2 с этим побороться?


    Чтобы узнать ответ, мы можем попросить JIT-компилятор вывести ассемблер сгенерированный для методов. Для этого нам потребуется установить hsdis. Потом можно воспользоваться удобными инструментами вроде JITWatch или написать JMH-бенчмарк и воспользоваться опцией -perfasm. Но здесь у нас пример простой, поэтому мы обойдёмся без сторонних инструментов и просто запустим виртуальную машину с такими волшебными параметрами:


    $ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintAssembly Test >output.txt

    Будьте осторожны: вывод этой команды может напугать маленьких детей. Но порывшись в нём, вы найдёте код, сгенерированный для нашего метода testIterator. Вот что сгенерировал C2 на платформе Intel x64 с кучей до 4 Гб:


    Ассемблер, можно не вчитываться
      # {method} {0x0000000055120518} 'testIterator' '(Ljava/util/List;)I' in 'Test'
      # parm0:    rdx:rdx   = 'java/util/List'
      #           [sp+0x20]  (sp of caller)
      0x00000000028e7560: mov    %eax,-0x6000(%rsp)
      0x00000000028e7567: push   %rbp
      0x00000000028e7568: sub    $0x10,%rsp         ;*synchronization entry
                                                    ; - Test::testIterator@-1 (line 15)
    
      0x00000000028e756c: mov    0x8(%rdx),%r10d    ; implicit exception: dispatches to 0x00000000028e75bd
      0x00000000028e7570: cmp    $0x14d66a20,%r10d  ;   {metadata('java/util/Collections$SingletonList')}
      0x00000000028e7577: jne    0x00000000028e75a0  ;*synchronization entry
                                                    ; - java.util.Collections::singletonIterator@-1
                                                    ; - java.util.Collections$SingletonList::iterator@4
                                                    ; - Test::testIterator@3 (line 16)
    
      0x00000000028e7579: mov    0x10(%rdx),%ebp    ;*getfield element
                                                    ; - java.util.Collections$SingletonList::iterator@1
                                                    ; - Test::testIterator@3 (line 16)
    
      0x00000000028e757c: mov    0x8(%rbp),%r11d    ; implicit exception: dispatches to 0x00000000028e75c9
      0x00000000028e7580: cmp    $0x14d216d0,%r11d  ;   {metadata('java/lang/String')}
      0x00000000028e7587: jne    0x00000000028e75b1
      0x00000000028e7589: mov    %rbp,%r10          ;*checkcast
                                                    ; - Test::testIterator@24 (line 16)
    
      0x00000000028e758c: mov    0xc(%r10),%r10d    ;*getfield value
                                                    ; - java.lang.String::length@1
                                                    ; - Test::testIterator@30 (line 17)
    
      0x00000000028e7590: mov    0xc(%r10),%eax     ;*synchronization entry
                                                    ; - Test::testIterator@-1 (line 15)
                                                    ; implicit exception: dispatches to 0x00000000028e75d5
      0x00000000028e7594: add    $0x10,%rsp
      0x00000000028e7598: pop    %rbp
      0x00000000028e7599: test   %eax,-0x27b759f(%rip)        # 0x0000000000130000
                                                    ;   {poll_return}
      0x00000000028e759f: retq   
      ... // дальше холодные пути

    Первое, что бросается в глаза — это краткость кода. С вашего позволения я прокомментирую, что тут происходит:


    // Стандартный стековый фрейм - подобным образом начинается всякий JIT-компилированный метод
    mov    %eax,-0x6000(%rsp)
    push   %rbp
    sub    $0x10,%rsp         
    // Загружаем идентификатор класса объекта из переменной list (указатель на объект пришёл в метод в регистре rdx).
    // Идентификатор класса лежит в объекте по смещению 0x8. Это похоже на вызов list.getClass().
    // При этом здесь происходит неявная проверка на null. Если окажется, что передали в метод null,
    // процессор сгенерирует аппаратное исключение в связи с обращением по запрещённому адресу.
    // Исключение перехватит виртуальная машина и заботливо транслирует его в NullPointerException
    mov    0x8(%rdx),%r10d
    // Сравниваем list.getClass() с идентификатором класса Collections$SingletonList. Этот идентификатор не меняется
    // за время работы JVM и, конечно, JIT его знает, поэтому это просто сравнение с константой
    cmp    $0x14d66a20,%r10d
    // Если list - это не SingletonList, выпрыгиваем на холодный путь
    jne    0x00000000028e75a0
    // Читаем приватное поле Collections$SingletonList.element в регистр rbp. Хотя указатели 64-битные, при размере кучи 
    // меньше 4 Гб верхние 32 бита всегда нули, поэтому виртуальная машина их не хранит и копирует только 32 нижних бита в ebp
    mov    0x10(%rdx),%ebp
    // Читаем идентификатор класса элемента и сверяем его с идентификатором класса String (аналогично тому, что выше)
    mov    0x8(%rbp),%r11d
    cmp    $0x14d216d0,%r11d
    // Если элемент списка - не строка, выпрыгиваем наружу на холодный путь (там будет создано и выброшено ClassCastException)
    jne    0x00000000028e75b1
    // Читаем приватное поле String.value в регистр r10. Это массив char[], в котором хранится сама строка
    mov    %rbp,%r10
    mov    0xc(%r10),%r10d
    // Читаем длину массива в регистр eax, который стандартно используется для передачи возвращаемого значения метода
    mov    0xc(%r10),%eax
    // Восстановление стекового фрейма
    add    $0x10,%rsp
    pop    %rbp
    // Проверка на safe-point. С её помощь JVM может забрать контроль у скомпилированного кода, например, для сборки мусора.
    test   %eax,-0x27b759f(%rip)
    // Выход из метода
    retq   

    Если кому-то всё ещё сложно это понять, давайте перепишем на псевдокоде:


    if (list.class != Collections$SingletonList) {
      goto SLOW_PATH;
    }
    str = ((Collections$SingletonList)list).element;
    if (str.class != String) {
      goto EXCEPTIONAL_PATH;
    }
    return ((String)str).value.length;

    Видите? На горячем пути нет ни цикла, ни выделения памяти под итератор, ни одного вызова метода. Всего лишь несколько разыменований и две быстрые проверки (которые всегда были ложны, поэтому предсказание ветвлений в процессоре отработает на ура). JIT-компилятор заинлайнил всё, что можно, понял, что итератор из метода не убегает, избавился от выделения памяти, развернул цикл и даже смог удалить флаг hasNext и связанные с ним проверки, статически доказав, что они не нужны! Сложение и переменная sum также испарились. И тем не менее, метод полностью корректен. Если окажется, что при следующем вызове ему передадут не singletonList, а что-то другое, он просто уйдёт на холодный путь (который, конечно, значительно медленнее). Остальные исключительные ситуации тоже обрабатываются. Можно передать null вместо list или подсунуть в список не строку (слава type erasure) — всё это будет обработано в соответствии с семантикой языка.


    Что же произойдёт, если сценарий работы программы изменится? Предположим, через некоторое время мы вообще перестали передавать в этот метод singletonList и передаём теперь всякие другие списки. На медленном пути виртуальная машина продолжает собирать статистику. Если она обнаружит, что медленный путь происходит сильно часто, JIT-компилятор перекомпилирует метод, убрав специальную обработку singletonList и вставив сразу честные виртуальные вызовы. Может ещё, кстати, сделать две ветки, если вы используете только две разные реализации списков. Этим JIT отличается от приложений скомпилированных заранее: исполняемый машинный код вашей программы может меняться, следуя за изменениями в её поведении.

    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 129

      –33
      Если бы JIT-компилятор круто оптимизировал, программы на Java работали бы быстро
        +23
        Если бы люди мерили реальную производительность реальных программ в реальных условиях, глупых холиваров и предубеждений было бы меньше
          +11
          А вообще в природе есть эти самые тесты реальных программ, которые показывают, что ява быстрая? Я как-то в основном натыкаюсь на тесты, которые этого, скажем так, не показывают. Т.е. мне действительно было бы интересно почитать такие сравнения с другими языками как раз на реальных программах, а не на тестах в 10 строк.
            +2
            Тестов таких не очень много, насколько я понимаю. Сложно найти программы/проекты на Java/C++ которые бы делали одно и тоже. Не так давно я где то видел сравнение tcp/ip библиотек, там библиотеки на Java были в топе, но это не совсем то.
              +3
              Ну я в свое время писал на джаве и на С++ некоторую математику и сравнивал. Там считались всякие хитрые хеши для изображения, по которым выполнялся потом их поиск, нужно было оценить потенциальную пользу от переписывания этой части в нативном коде. Деталей самой математики честно говоря уже не помню, да и NDA, все дела, но там было несколько вполне весомых файлов с кодом, тензоры всякие, свертки, какие-то страшные формулы которые по маске считались для каждого пикселя картинки и т.п.

              Ну так вот, при этом код на С++ оказался впереди на считанные проценты времени. Выигрыш был бы съеден дополнительными расходами на вызов через JNI, поэтому от переноса мы решили отказаться. Это был код который делает много вычислений, но особо не аллоцирует память и в целом в С++ переносится практически один-в-один.

              Так что именно перемалывание циферок у них примерно одинаково. За счет «оптимистичных оптимизаций», приведенных в статье, джава может даже вырываться вперед иногда.
                0
                Это, кстати, достаточно естественно выглядит. Т.к. математика напрямую отображается в команды процессора без особых накладных расходов. Как я понимаю, основные проблемы возникают при работе с памятью. Т.е., допустим, я не могу накопить массив байтов и потом конвертировать его в строку без копирования. И подобные копирования в очень многих местах при работе с java встречаются. В то же время на c/c++/rust подоных копирований можно избежать не теряя читабельность кода и не изобретая свои велосипеды под конкретные случаи.
                  +4
                  Т.е., допустим, я не могу накопить массив байтов и потом конвертировать его в строку без копирования.
                  А как вы это в C++ сделаете?

                  В то же время на c/c++/rust подоных копирований можно избежать не теряя читабельность кода и не изобретая свои велосипеды под конкретные случаи.
                  Я боюсь что «без велосипедов» не получится. Другое дело, что стиль написания с передачей фрагментов буфера туда-сюда в Java выглядит как-то что исключительно кривое и, скажем так, инородное. А в C++ — это один из типичных стилей написания программ. Но это скорее вопросы культуры и стиля.

                  Проблема Java в том, что весь этот код, из которого JIT'ы умеют делать «конфетку» — он нифига не идеоматичен. А идеоматичный код (со всякими фабриками фабрик фабрик, DI через отражение или, что ещё «круче», через XML-конфиг) ни один JIT вам ни во что вменяемое не превратит…
                    0
                    Не для всякого кода важна производительность. Что плохого в том, что сервис стартует на пару секунд больше, если основная его задача выполнять свои функции без сбоев на протяжении месяцев?
                  +1
                  Тут знаете есть небольшое возражение:

                  В области обработки изображений для алгоритмов характерен высокий параллелизм и не требуется, как правило, высокая точность (что позволяет часто использовать в вычислениях числа с фиксированной точностью). Эти характеристики позволяют в большинстве случаев очень эффективно задействовать SIMD, которые сейчас поддерживают практически все современные процессоры. Так вот задействование SIMD позволяет в среднем получить дополнительный выигрыш на порядок. С++ позволяет эффективно задействовать SIMD при помощи интринсиков. Как с этим у Java?

                  А так да, я сам лично проводил сравнение кода (без SIMD оптимизаций) на С++ и C# — и еще лет 6 назад выигрыш С++ не превышал 30%, что делало не актуальным простое переписывание кода из managed языков на С++).
                    +1

                    Насколько я знаю, HotSpot JIT может применить SIMD, но на довольно ограниченном наборе паттернов.

                      0
                      Ну так и в С++ для многих компиляторов есть автовектоизация, которая на простых случаях достаточно эффективно работает. Но как только шаг в сторону — и приходится ручками все допиливать.
                        0

                        В рамках Project Panama двигают нормальные ассемблерные вставки в Java-код, без всякого JNI. Может в Java 10 что-нибудь выкатят.

                        0
                        На эту тему у Nitsan Wakart есть прекрасная статья (я думаю вы её уже видели).

                        Ещё раз спасибо за статью :) Ну и по теме.

                        Я, таки, попробовал на ArrayList'e из одного / двух элементов — там таких эффективных оптицизаций нет.

                        За то если параметр заменить на String[]testIterator(String[] array) и передавать туда new String[] { «abc» }, то он вообще схлопывается в константу «3», а внешний цикл на 1 000 000 итераций анроллится (хотя я техническое дно в ASM и могу ошибаться).
                        +2
                        Для Windows Store приложений уже опять актуально, т.к. часто вызовы платформы идут через границу Managed и Unmanaged, что может занчительно нагнуть производительность C# кода.
                        Опять же на C++ в сравнении с C# в рамках платформы без доступа к unsafe можно не слабо сэкономить на работе с массивами.
                        Я при переходе с C# на C++ для расчета данных треков, выиграл чуть больше чем в два раза, правда после перехода на DXMath, который перенес математику на SSE и Neon, выигрыш стал намного более значительным.
                          0
                          Project Sumatra мог бы значительно поднять производительность jvm, работающей на APU по сравнению с JIT компилятором с SIMD инструкциями и регистрами. Но проект похоже не развивается…
                        +1

                        Например, https://www.techempower.com/benchmarks. Java там стабильно в лидерах.

                          –3
                          –1
                          Люди не меряют. Люди пользуются. Человек есть мера всех вещей. И люди видят, что программы на java работают медленно. Ну, хорошо, не все это видят, те у кого топовый компьютер — могут и не заметить. Но, в общем-то, факта это не меняет.

                          Даже прочитав эту статью у меня возникает недоумение: фраза «Этим JIT отличается от приложений скомпилированных заранее: исполняемый машинный код вашей программы может меняться, следуя за изменениями в её поведении.» подразумевает, что JIT чем-то лучше… но постойте… В приложении, скомпилированном заранее, в процессе работы выполняется только приложение. В случае же с JIT — параллельно работает ещё и компилятор, который к тому же собирает статистику! Даже если приложение за счёт адаптации к изменениям в поведении станет работать быстрее — работа компилятора всё равно съест весь прирост.
                            0

                            Компилятор много работает на старте приложения. Через несколько минут интенсивной работы доля CPU, съедаемая компилятором, уже невелика. Кроме того редко когда у вас все ядра загружены, а компилятор асинхронно работает.

                              0
                              Вы знаете какой у меня ПК, и как часто у меня загружены все ядра? Прекратите следить за мной!
                              К слову, на рабочем компе не редка ситуация «Загружены все ядра», ибо компьютер там слабый. По странному стечению обстоятельств, эта ситуация почему-то совпадает с отладкой java-приложений в IDE, написаном на java.
                              Я нисколько не умаляю достоинств JIT — я охотно вам верю, что если бы не он — java тормозила бы на порядок больше. И того, что использовани java зачастую оправдано — я тоже не отрицаю. Но, будем честны, быстродействие — это не сильная сторона java.
                                +2
                                Может будем честны до конца: быстродействие Java на многих классах задач сравнима (чуть хуже/чуть лучше) с производительностью, получаемой на c++?

                                PS да, разработка на java требует компьютера посерьёзней, чем простой офисный. И по памяти и по мощности cpu желателен буст. Впрочем всё это нужно для ускорения разработки, которая и без того зачасту быстрее разработки программ на c++.
                                PPS я знаю, что теоретически из c++ можно выжать много больше, знаю, что на некоторых классах задач он будет рвать java как тузик грелку. Вообще c++ выбран как пример языка, программы на котором очень часто сравнивают по производительности с программами на java.
                                  +1
                                  быстродействие Java на многих классах задач сравнима (чуть хуже/чуть лучше) с производительностью, получаемой на c++?
                                  Нельзя сравнивать «быстродействие на многих классах задач». Можно сравнивать «определённым способом написанный код».

                                  Всё упирается в один простой факт: работа с таким массивом
                                  struct {
                                    int x;
                                    int y;
                                  } array1[100];
                                  
                                  в несколько раз быстрее, чем с таким
                                  struct {
                                    int x;
                                    int y;
                                  } (*array2)[100];
                                  


                                  И всё что делает JIT — пытается всеми правдами и неправдами превратить array2 в array1.

                                  К огромному сожалению для людей, вынужденных пользоваться программами на Java весь язык, все библиотеки и вообще вся экосистема построены на превращении из array1 в array2. Многократном и повсеместном. Никакой JIT тут не спасёт.

                                  А главное — в программах где array1 доминирует всё ради чего затеяны все сложности, которые героически решают разработчики JIT'ов не нужны. Если нет бесконечных уровней индирекции и запутанных иерархий абстракий, то не так сложно отследить — кто чем владеет, а значит не нужен GC. Раз не нужен GC и типы заранее известны — то все навороты типа «est %eax,-0x27b759f(%rip)» — тоже не нужны. И так далее.

                                  Вообще c++ выбран как пример языка, программы на котором очень часто сравнивают по производительности с программами на java.
                                  И всё всегда сводится к одному вопросу: а почему, собственно, если JIT так крут — то почему все программы на Java тормозят? А если программы всё равно тормозят — то о какой «крутости» вы тут говорите?

                                  И обе стороны по своему правы. А истина — посередине: JIT-компиляторы, несомненно, круты, но проблема в том, что они, по большей части, решают задачу которой вообще не должно было быть!
                                    +1
                                    все программы на Java тормозят

                                    Список можно? А то уже несколько людей говорят, что всё на java у них тормозит, но почти ни одного названия тормозящих программ нет. Ну и ещё конфигурацию компа, на котором всё это тормозит.


                                    А то у меня на рабочем компе вполне могут работать 2 экземпляра IDE, запущен хром и фф. Ничего из этого не тормозит, хотя конфигурация далеко не топовая.

                                      –4
                                      Вам перечислить список всех существующих программ на java? Боюсь список получится несколько, эмм, длинноват. А вы можете дать список программ на java, которые не тормозят?
                                        +4
                                        Вам перечислить список всех существующих программ на java?

                                        Нет, хотел увидеть список программ, которыми вы реально пользовались и которые тормозили при этом.


                                        А вы можете дать список программ на java, которые не тормозят?

                                        Могу назвать те, которыми пользуюсь я.
                                        Например, IDE от JetBrains. После запуска, построения индекса и загрузки кэша работают шустро.
                                        Ещё при работающей IDE только что запустил 2 профайлера (JProfiler и YourKit Java Profiler). Каждый из них работал без тормозов: интерфейс отзывчивый, фризов не наблюдал.


                                        Больше я особо не припомню java-приложений, которыми пользуюсь. А называть всё подряд и говорить "не тормозит" я не буду. Но если уж такие программы работают шустро, то и более мелкие не должны тормозить.


                                        PS Запустил SweetHome 3D для проверки. Работал без тормозов, но я особо не добавлял объектов, так что точно не могу сказать.


                                        Система: linux, oracle vm 64bit, 8GB RAM, Core i5 2.2GHz.

                                          +3

                                          Сталкивался с одним коллегой, который говорил, что его демо прога на C# работает быстрее чем на Java. Суть была в плавной смене цветов в квадратах (на форме девять квадратов) и якобы на Java это медленнее. В ходе разбора выяснилось, что просто на Java он кривой код написал — переписали и визуальной разницы перестали замечать.
                                          Вывод: тормозит не JVM, а кривой код на ней

                                +4
                                И люди видят, что программы на java работают медленно

                                А какие программы? Просто чтобы сравнивать более объективно, нужно брать продукты примерно одного уровня с идентичными возможностями на разных языках.


                                У меня, например, из десктопных java-программ есть только IDE (Idea). Ну да, они тормозят. Точно так же, как и IDE на C++ (Visual Studio). Да и то, тормоза в идеи в основном только при индексации проекта.


                                Ещё любят упоминать Minecraft как пример тормозной java-программы. Там тормоза связаны с недостаточной оптимизацией самой игры (по крайней мере, Нотч не особо оптимизировал, как сейчас там дела я не знаю). Ну и тормозило там всё в основном при генерации новых чанков, что вполне понятно. Ну и опять же, как будто подобные игры на C++ не тормозят.


                                Так может программы на java тормозят не потому что на java, а потому что они просто либо очень сложные, либо плохо оптимизированны, а язык и платформа тут не вносят существенных тормозов?

                                  –1
                                  Ну вот давайте я тоже сравню IDE. Запускаю netbeans — тормозит до невозможности работать. Запускаю Visual Studio — ничего не тормозит, единственные тормоза — на этапе компиляции. Я как-то не так сравниваю? Это не единственный подобный случай, просто если уж вы заговорили об IDE — то привожу свой опыт. Но с другими java-программами опыт примерно такой-же. Это случается настолько часто, что когда у меня что-то тормозит — я проверяю, не на java ли оно написано. Не всегда, но часто — угадываю.
                                    +1
                                    Года 3 назад приходилось править софт, написанный на C#. WPF, XAML и прочие .NET технологии. Так вот стоило открыть пару в меру сложных WPF-форм, как VS и вся рабочая станция вместе с ней начинали дико тупить. Любой достаточно тяжелый софт можно нагрузить так, что начнет тормозить не только он, а и все остальное.
                                      0
                                      Так у C# те же проблемы что у java.
                                        –2
                                        Не совсем. Многие проблемы managed-языков можно сделать менее острыми глубоко интегрировав их в систему (Лисп-машины имели смешную, по современным меркам, производительность, однако были вполне себе отзывчивы за исключением этапа загрузки и «прогрева» системы… Android на Java — это тоже «ужас», а не «ужас-ужас-ужас» — по той же причине) — но в целом, да, проблемы схожи.

                                        P.S. Моё мнение обо всём этом managed безумии сложилось во времена WRT.EXE из Borland C++ 2.0. Который нещадно тормозил и требовал «невероятных» (по тем временам) ресурсов (при отвратительной функциональности, надо сказать). Через год вышел Borland Resource Workshop и про тормоза все забыли. Вспомнили когда началась вся эта истерия вокруг Java — и до сих пор слышим мантры про то, какой крутой Java JIT и что тормоза — это фигня, главное — функцинальность. Увы, но тормозят C# и Java всегда, а функциональность… — может быть, может не быть…
                                    0
                                    Если я правильно помню, то студия начиная с 2012 (или 2013) переписана на WPF, что нифига не плюсы. Компилятор (привет Rosylin) тоже переписан на шарпы. Из ключевых плюсовых компонент остается только msbuild, но он прямого отношения к студии не имеет, и причиной тормозов как правило не является.
                                    +2
                                    Фразой про необходимость (корректных) измерений я хотел сказать что совсем не очевидно что быстрее — программа на C++ или на Java.

                                    Многие распространенные мифы про тормознутость Java строятся на (не совсем корректных) прикидках.

                                    Ну вот давайте и прикинем. Известно что узкое место в работе (нормального) компьютера это доступ в память. Разработчику не жалко потратить десятки а иногда сотни тактов процессора чтобы избежать лишнего доступа в кеши процессора или в оперативку. 90% времени процессор пользовательского компа простаивает в ожидании подгрузки чего-нибудь из памяти.

                                    Когда загружается программа на C, это более-менее полотно ассемблерных инструкций для всех возможных веток выполнения программы. Вроде понятно.

                                    Когда загружается Java программы, она состоит из JVM байт-кода и интерпретатора JIT. А теперь фокус: байткод и интерпретатор зачастую вместе занимают меньше места чем соответствующий ассемблер. Этим экономится драгоценное место в памяти и кешах. Достигается это тем что JVM байт-код это хорошо упакованные высокоуровневые инструкции, которым могут соответствовать десятки команд ассемблера.

                                    Вот так и получается что действия, которые выполняются относительно редко (95% всей логики), логично интерпретировать. Действия которые выполняются часто и влияют на производительность «распаковывают» из байт-кода в машинные команды различной степени оптимальности.

                                    Когда Вы запускаете IDE вроде IntelijIdea, 5 минут в начале она подтормаживает, происходит тот самый «прогрев» — инициализация и распаковка кода. После этого она начинает ускорятся, и через полчаса летает (это мои собственные ощущения). Готов поспорить что если гипотетически скомпилировать ее в машинные команды (реально не получится ибо рефлекшн), то эти 5-20 минут разогрева потратятся просто на загрузку разбухшего кода в память и прогрев кешей.
                                      –1
                                      Вы знаете, меня как пользователя — мало волнуют измерения. Я говорю о субъективных ощущениях, которые возникают при пользовании программой написаной на C/C++ и программой написанной на java. Так вот, эти ощущения таковы, что когда я работаю с программой на java — меня не оставляет ощущение тормознутости. Это не абсолютно измеренное быстродействие, это совокупность факторов «сколько я трачу времени на ожидание завершения очередного действия» + «насколько отзывчив интерфейс» + «насколько это влияет на исполение других программ». Если во время работы с некоторой программой, я обнаруживаю, что реакция на пользовательский ввод происходит с существенной задержкой, мне приходится ждать, когда программа выполнит очередное действие — я говорю, что программа «тормозная». Если при этом и другие программы, до этого работавшие «нормально», стали проявлять те же признаки — я говорю «программа тормозит весь компьютер». Так вот, этими эпитетами я награждаю программы, написанные на java на порядок (а может и на пару порядков) чаще, чем программы, написанные на C/C++. Я не берусь делать выводы о причинах — возможно, это просто нерепрезентативная выборка, и мне не везло, возможно — это недостаток хороших программистов, пишущих на java, из-за низкого уровня вхождения в язык, возможно — это таки следствие реально более низкого быстродействия. А может быть, тут совокупность всех этих факторов, это мне кажется наиболее вероятным.
                                      Ну и в «и интерпретатор зачастую вместе занимают меньше места чем соответствующий ассемблер.» мне как-то верится с трудом. К сожалению, полноценно это утверждение проверить не удастся, ибо это будет либо компиляция каких-то синтетических тестов, либо и вовсе несравнимые вещи.
                                        –1
                                        Я не берусь делать выводы о причинах — возможно, это просто нерепрезентативная выборка, и мне не везло, возможно — это недостаток хороших программистов, пишущих на java, из-за низкого уровня вхождения в язык, возможно — это таки следствие реально более низкого быстродействия. А может быть, тут совокупность всех этих факторов, это мне кажется наиболее вероятным.
                                        Причина, конечно, не в JIT'е. Прична — в том, что изначально вся архитектура Java'ы сделана так, что железу исполнять программы не просто трудно, а черезвычайно трудно. Как известно все проблемы в информатике можно решить с помощью дополнительного уровня абстракции… за исключением проблемы слишком большого количества абстакций. А проблемы со скоростью и излишним потреблением памяти — это и есть проблемы слишком большого количества абстракций в 99 случаях из 100.

                                        За то время пока вы сходите в память разименовать один указатель процессор успеет обратить матрицу 10x10… или отсортировать массив на 100 элементов… или ещё что-нибудь подобное посчитать. А у вас тут фабрики фабрик фабрик, DI и отражения… которые все, что характерно, построены на бесконечных индирекциях…

                                        Можно ли написать на Java код так, чтобы он был быстрее, чем код на C/C++? Да, разумеется. Но для этого вам потребуется программист с опытом работы на FORTRAN или C++, а не Java. А такому программсту, представьте себе, проще и удобнее писать на FORTRAN или C++!
                                          +1
                                          я говорю «программа тормозит весь компьютер»

                                          Допустим, в системе запущен браузер, ещё пара мелких приложений. Всё это дело потребляет 3Гб из 4-х. Всё работает без тормозов. Я запускаю IDE, памяти не хватает, всё начинает жутко лагать. Кажется, что ИДЕ затормозила всю систему…
                                          Теперь другая ситуация: запущена IDE, пара мелких приложений. Память не израсходована до конца, всё летает. Я открываю в браузере кучу вкладок, память кончается, всё тормозит. Кто теперь виноват в тормозах?
                                          Тут не IDE тормозит всю систему, и не браузер, а совокупность факторов. Лично по моему опыту, всё начинает тормозить, когда память подходит к концу. Да, зачастую java-приложения довольно прожорливы в плане памяти.


                                          Ещё есть такой момент: количество потребляемой памяти для java-программы можно ограничить через JVM. Если программа по какой-то причине не укладывается в кол-во выделенной ей памяти — она обычно начинает тормозить. А вот кол-во памяти потребляемой программой на C++ ограничить уже не так просто. Она может отъесть очень много ОЗУ. В таком случае может просто случиться так, что JVM не сможет выделить много памяти приложению, и оно будет тупить, при этом всё остальное тормозить не будет.


                                          Кстати, можете привести пример java-программ для десктопа, которые у вас тормозили? Просто я кроме IDE и сопутствующих утилит особо не запускал. И IDE у меня тормозит только при запуске/индексации. Ну или когда вся память закончилась (но тогда тормозит всё, и дело тут уже не в java).

                                            0
                                            Ещё есть такой момент: количество потребляемой памяти для java-программы можно ограничить через JVM.
                                            Нельзя, не рассказывайте сказок. Можно ограничить количество памяти, которое JVM будет сжирать без всякой причины.

                                            А вот кол-во памяти потребляемой программой на C++ ограничить уже не так просто.
                                            ulimit кто-то отменил? Только в случае с C++ — это «ремень безопасности», грамотно написанная программа на C++ не должна потреблять лишней памяти (и не делает этого на практике). Только не надо про браузеры — современные браузеры, увы, это не «просмотрщики гипертекста», как они задумывались, а интерпретаторы-переростки для языка, который пытается доказать, что Java — это всего лишь «ужас», а не «ужас-ужас».

                                            Кстати, можете привести пример java-программ для десктопа, которые у вас тормозили?
                                            Тормозит всё, что я запускал. IDEA, Vuze, даже какие-нибудь мелкие утилитки типа Keypass'а (это, правда, C# — но принцип тот же).

                                            Разумеется у меня на десктопе (64GiB RAM, Dual Xeon, 24 ядра, 48 потоков) — проблем нет. Но стоит мне пересесть на «печатную машинку» моей сестры (2GiB RAM, Atom) — всё, можно умереть.

                                            Только не надо про «ну чего вы хотите от такой системы»: я хочу чтоб работало. И если для программы на C/C++ мне нужна машинка за $100, а для программы на Java для получения одинакового «фана и экспиреенса» — за $10'000, то это, у нормальных людей, не обременённых глубокими познаниями в IT, и называется «тормозит».
                                              +2
                                              грамотно написанная программа на C++ не должна потреблять лишней памяти (и не делает этого на практике)

                                              Как и на любом другом языке.


                                              Тормозит всё, что я запускал. IDEA, Vuze

                                              Ну вот, наконец-то назвали вторую тормозящую программу. Конкретно про Vuze не могу ничего сказать. (помню только, что это большой комбайн, включающий в себя кучу всего нужного и не очень).


                                              А вот про идею...


                                              (2GiB RAM, Atom)
                                              я хочу чтоб работало
                                              И если для программы на C/C++ мне нужна машинка за $100, а для программы на Java для получения одинакового «фана и экспиреенса» — за $10'000

                                              А назовёте программу на C++, которая имеет одинаковый фан и экспириеенс, сравнимый с IDE от JetBrains? И чтобы при этом она работала на таком ноуте (2GiB RAM, Atom).
                                              Я вот не знаю такой. Может быть, когда она появится, на таком ноуте она тоже будет тормозить… В любом случае, сравнить Idea пока не с чем.


                                              В общем, пока что тормозит только Idea на откровенно слабой для неё системе, и Vuse, а больше названий я не увидел. Но 2 программы это далеко не всё что есть в мире java.

                                                –1
                                                Ну вот, наконец-то назвали вторую тормозящую программу.
                                                Как вы думаете — почему мне так сложно это сделать? Потому что я не люблю Java? Нет — потому что я не люблю тормоза. И в результате программ на Java у меня не мало, а очень мало. И они все — начиная от IDE и кончая нашими внутренними системами сборки — страшные монстры жрущие ресурсы «как не в себя».

                                                Тут вас просили: приведите лучше примеры реально программы на Java, которая «летает» — а мы сравним её с аналогом на C++. Только не бенчмарк, а реальную программу, пожалуйста.
                                                  +1
                                                  Тут вас просили: приведите лучше примеры реально программы на Java, которая «летает» — а мы сравним её с аналогом на C++.

                                                  https://habrahabr.ru/post/305894/#comment_9709242


                                                  Вот только сравнивать-то особо не с чем. IDE от JetBrains по фичам далеко впереди студии, а уж других ИДЕ и подавно. Профайлеры jvm написанные C++ вряд ли есть.

                                                    +3
                                                    Потому, что аналогов не существует. Vuze просто хреноватенько написан, но я им пользусь, потому что мю-торрент в какой-то момент начала втихую ставить майнеры биткоинов.

                                                    флеш плеер у вас тормозит? Насколько знаю, он активно использует жава код, просто неявно. На самом деле, жаву использует много прог, но вы про это просто не догадываетесь. Они статически прилинковали libjvm — и юзают ее. Они не тормозят — и поэтому вы думаете что это не java.

                                                    Пример из жизни — json_spirit ел 80% проца, qt json парсер — ест около 15 (и при этом он архитектурно убог, что такое container factory — авторы еще лет 10 знать не будут). java-парсер ест 1...5% (что в пределах погрешности). Правда, пришлось написать свой парсер, с плюшками. Стандартные убоги, с неправильно расставлеными try-catch и неверной архитектурой. Стандартные тоже наверное подтормаживали бы.

                                                    Так что, на плюсах тоже дохрена тормозящих приложений. Просто считается, что если тормозят плюсы — это хреново написаное, а если тормозит на java — это «тормозит java».
                                                      0
                                                      Флеш плеер — одна из самых тормозящих программ, известных миру. Благодаря вам, я наконец узнал, почему.
                                                  0
                                                  А теперь проведём мысленный эксперимент: поставим на этот ваш «печатную машинку сестры» MS Visual Studio — ну как, не тормозит? Других очень толстых (по объёму предоставляемого функционала) не-java IDE не вспомню сходу… Разработка ПО изначально не приспособлена эффективно работать на дохлых машинах.

                                                  Про Vuze — на практике знаю, что были нормальные сборки, были тормозные. Это не от языка зависит. Помнится натыкался на пару клиентов вполне себе плюсовых, которые тормозили не слабее.
                                                    0
                                                    А теперь проведём мысленный эксперимент: поставим на этот ваш «печатную машинку сестры» MS Visual Studio — ну как, не тормозит?
                                                    Visual Studio 6? Нет — не томозит. .NET был частично переписан на CLR для получения «фана и экспириенса» с покупкой нового железа, увы.

                                                    Разработка ПО изначально не приспособлена эффективно работать на дохлых машинах.
                                                    Нет — это совренные IDE не рассчитаны на это. Только не надо про reflection и прочее. Visual Basic или старые версии Delphi без CLR точно также позволяли и формочки таскать и свойста типов смотреть и многое другое. Потребляя в разы меньше ресурсов.
                                                      +2
                                                      А вы более древнюю VS могли назвать? Она не тормозит не потому, что вся из себя такая хорошая, а потому, что функционал у неё резко меньший.
                                                      Давайте прикинем по требованиям: если я правильно помню 200 метров оперативки ей хватало за глаза. Современная IDE от JetBrains в полном фарше на среднем проекте съедает гиг. При том, что у вас всего 2 гига на одноядерном атоме, полюбому, в винде…
                                                      В общем у меня на такой конфигурации тормозит _всё_ ПО… Java, браузеры, системные утилиты, да даже сама ОС.

                                                      Современные IDE не рассчитаны на использование питекантропами, например, и что? Они дают функционал. Много функционала. Функционала который ускоряет кодирование, функционала, который помогает бороться с ошибками. За всё нужно платить. Ну а если вам достаточно этих динозавров, так почему бы сразу на vim не уйти?
                                                      Так что предоставляя НА ПОРЯДКИ худший функционал они потребляют В РАЗЫ меньше ресурсов. ИМХО невыгодный обмен.
                                                        0
                                                        А вы более древнюю VS могли назвать?
                                                        Мог бы. Они тоже не тормозят :-)

                                                        Давайте прикинем по требованиям: если я правильно помню 200 метров оперативки ей хватало за глаза.
                                                        200 метров? Вы, я извиняюсь, ох$нели? 20-30MiB. Больше — если операционка требует больше. На своём Pentium MMX с 64MiB памяти я спокойно ей пользовался под Windows 95 OSR2, на машинках с 16MiB — да, были тормоза, скорее всего на 32MiB она бы «слегка подтормаживала при запуске». Если Windows 2000 поставить или XP, то да, потребуется больше — но тут не в Visual Studio дело.

                                                        Современная IDE от JetBrains в полном фарше на среднем проекте съедает гиг.
                                                        Я не знаю что такое «средний проект». Кому и Chromium (на котором Visual Studio, я извиняюсь, «сворачивается в трубочку») — «средний проект». Но на «Hello, world!» уже требуются сотни мегабайт.

                                                        Она не тормозит не потому, что вся из себя такая хорошая, а потому, что функционал у неё резко меньший.
                                                        Не надо про «функционал», пожалуйста. Даже если отключить в Visual Studio .NET или IDEA вообще всё что можно — они тормозят. Менюшки медленно открываются, переключение между закладками тормозит, да даже если просто текст набирать — можно тормоза заметить.

                                                        В общем у меня на такой конфигурации тормозит _всё_ ПО… Java, браузеры, системные утилиты, да даже сама ОС.
                                                        Мне вас жаль. А у моей сестры её любимый MS Office 2000 не тормозит. И Chrome — тоже. И даже MPC не лагает, представьте себе!

                                                        Современные IDE не рассчитаны на использование питекантропами, например, и что? Они дают функционал. Много функционала.
                                                        Давайте не переводить стрелки, а?

                                                        Исходный тезис был прост: Java == неумеренное потребление ресурсов — в первую очередь памяти, но и CPU тоже.

                                                        Этот тезис вашими рассказами про «много функционала» ничуть не опровергается. Скорее наоборот.

                                                        Ну а если вам достаточно этих динозавров, так почему бы сразу на vim не уйти?
                                                        Кто вам сказал, что я не использую Vim?

                                                        Так что предоставляя НА ПОРЯДКИ худший функционал они потребляют В РАЗЫ меньше ресурсов. ИМХО невыгодный обмен.
                                                        Когда как. IDEA я тоже иногда использую (правда реже, чем тот же Vim).

                                                        Но правда заключается в том, что в теории возможны четыре варианта:
                                                        1. Программы, которые требуют чудовищное количество ресурсов и мало чего умеют.
                                                        2. Программы, которые требуют чудовищное количество ресурсов и обладают развитым функционалом.
                                                        3. Программы, которые не требуют особо много ресурсов и мало чего умеют.
                                                        4. Программы, которые не требуют особо много ресурсов и обладают развитым функционалом.

                                                        Вы утверждаете, что программы из квадранта 4 были вытеснены программами из квадранта 2 — что правда. Программ из квадратна 4 мало и со временем они, обычно, отстают от программ из квадранта 2 (к возможностям Оберон-системы IDEA шла годы, хотя сейчас, конечно, она получила много новых фич), но проблема в том, что Java напрочь исключает квадранты 3 и 4.

                                                        И никакие рассказы про «много функционала» этого не изменят. Да и вообще, мы статья обсуждаем про что? Про то, что «JIT-компилятор оптимизирует не круто, а очень круто»! Ну и хде? Хде эта оптимизация? Почему нам опять поют песни про функционал, а не про то, что это позволяет встроить Java в систему управления холодильников за три с половиной цента?
                                                          +1
                                                          Почему нам опять поют песни про функционал, а не про то, что это позволяет встроить Java в систему управления холодильников за три с половиной цента?

                                                          Эта часть шкалы тоже представлена в J2ME, JavaCard и всяких минималистичных OSGi-профилях. Только функциональность там урезанная, естественно.

                                                            0
                                                            Вот с этого момента — поподробнее. Про JavaCard — давайте не будем: этот высер во-первых имеет мало отношения к Java (вы реально хотите говорить что язык без динамической памяти и «кучи» можно назвать Java'ой?), а во-вторых — оно жрёт примеро вдвое больше ресурсов, чем альтернативные решения без маркетинговой составляющей.

                                                            J2ME — почил в бозе, слава богу. О покойниках либо хорошо, либо ничего.

                                                            А где применяются «минималистичные OSGi-профили»? Нет, мне правда интересно. Неужели какое-то из обещаний, которые помогли «продать» Java (напомню что изначально вся петрушка затевалась ради IoT (тогда, правда, это направление проходило под кодовым названием «Smart Appliances»), но, традиционно для Java, из этого ничего не вышло. Неужели кто-то ещё «не наелся»?
                                                              0

                                                              Часть OSGi профилей можно отнести к эпохе J2ME (всякие CDC environment). Из более тяжелых вещей — Eclipse Kura, например. Оно живёт и развивается, но я не знаю, кто использует в боевом режиме.


                                                              Другой пример — microej, список клиентов вполне неплох. Ещё на ум приходит Excelsior JET Embedded с их AOT-компилятором.


                                                              У меня тоже сложилось впечатление, что в основном использование java в embedded — это hype (как и прошлый заход с jazelle), но то что ощутимое число фирм её пилят намекает, что покупатели есть. Всякие entertaiment-системы, HMI и т. п., где очень хочется взять толпу индусов и быстро выкинуть продукт на рынок.


                                                              При использовании ARM9/ARM11/Cortex-A с разумным количеством памяти использование java выглядит вполне реалистично.

                                                                +1
                                                                У меня тоже сложилось впечатление, что в основном использование java в embedded — это hype (как и прошлый заход с jazelle), но то что ощутимое число фирм её пилят намекает, что покупатели есть.
                                                                А я вот в этом — совсем не уверен. Java — это такой мыльный пузырь, вокруг которого — куча шума и очень мало сути.

                                                                Jazelle — это такая себе типичная Java-история: мы сделаем технологию, которая будет ускорять Java и внедрим её во все наши процессоры, вау! Звучит круто, заманчиво. Но когда начинаешь разбираться, то выясняется, что в результате — вышел пшик: Jazelle призвана исполнять определённый процент операций «в железе» и при этом она реализована во всех, без какого-либо исключения процессорах после ARM7EJ. Круто, да? Но есть одна маленькая беда: процент ускоренных операций может быть нулевым, а начиная с ARMv8 он обязан быть нулевым!

                                                                И вот так — веде и всюду. Сплошной Изумрудный город. Когда нет возможности сделать всё вокруг из настоящего изумруда — мы раздаём всем жителям и посетителям очки с зелёными стёклами.

                                                                Как вы думаете — почему я так резко отрицательно отношусь к Java и достаточно спокойно — скажем к C#? С чисто технической точки зрения — это почти одно и то же, но разработчики C# — не лицемерят. Они не пытаются выдать нечто без колёс и мотора за «удешевлённое авто» и нечто без крыльев и не летающее — за самолёт.

                                                                Если им не удаётся сделать так, чтобы приложение на управляемом коде работало так же быстро, как нативное — они об этом честно говорят, делают возможность вызывать нативный код из CLR и на этом успокаиваются.

                                                                Подход же Java — это продолжать заявлять «что скорость работы Java-приложения мало отличается от скорости работы приложения на C++» (притом что увидеть ложность этого высказывания, в общем, не составляет труда), говорить о том, что нечто без байткода и управления памятью — это по прежнему Java (но только когда это делает Sun/Oracle, конечно — когда то же самое делает Google, то это, разумеется, страшный грех и нужно за это отсудить 100500 миллиардов), называть чёрное белым и вообще делать вид, что небо у нас — зелёное (если так партия сказала). Но признать свою ошибку и назвать белое белым, а чёрное чёрным? Нет, этого сделать никак нельзя!
                                                            +1
                                                            > 200 метров? Вы, я извиняюсь, ох$нели? 20-30MiB. Больше — если операционка требует больше. На своём Pentium MMX с 64MiB памяти я спокойно ей пользовался под Windows 95 OSR2, на машинках с 16MiB — да, были тормоза, скорее всего на 32MiB она бы «слегка подтормаживала при запуске». Если Windows 2000 поставить или XP, то да, потребуется больше — но тут не в Visual Studio дело.

                                                            Можете не извиняться, вам это не подходит. Ну а конкретную размерность я уже не помню. По Win95 — извините, но она сама жрёт минимум те самые 16 мегабайт — без свапа вы на 32х метрах очень мало что запустите… и покрашитесь с невозможность аллоцировать память. Скорость дисков того времени вам напомнить? Оно не смогло бы не тормозить. Ну а по накладным расходам — спасибо, что сами о них написали. Не придётся тыкать носом. На той вашей сестринской «печатной машинке» какая ОС? Сколько она оперативки выжирает? Ну а в отличие от производительности — с памятью вопросов нет, Java действительно её любит. Тому же Idea очень хочется скушать около гига. И начинается та же свистопляска со свапом… И это, по вашему, java виновата?

                                                            >Я не знаю что такое «средний проект». Кому и Chromium (на котором Visual Studio, я извиняюсь, «сворачивается в трубочку») — «средний проект». Но на «Hello, world!» уже требуются сотни мегабайт.

                                                            Средний проект — порядка 100 тысяч строк кода (включая аннотации и всяческие xml типа спрингового контекста). Не на «hw» требуются сотни мегабайт а на функциональность, которая позволяет эффективно работать с крупными проектами (включая кеши различных уровней, например AST, синтаксический анализатор и прочие плюшки).

                                                            > Не надо про «функционал», пожалуйста. Даже если отключить в Visual Studio .NET или IDEA вообще всё что можно — они тормозят. Менюшки медленно открываются, переключение между закладками тормозит, да даже если просто текст набирать — можно тормоза заметить.

                                                            Т.е. механизмы (архитектуру) подключения этого функционала вы игнорируете? Кастомизируемость UI тоже побоку? Вы физически не можете отключить все плюшки современных IDE. Только снизить их количество. Ну и на Intel Atom c 2мя гигами оперативы… у меня вот в такой конфигурации браузеры тоже только в путь тормозят… Они, видимо, тоже на managed языках написаны, да?

                                                            > Мне вас жаль. А у моей сестры её любимый MS Office 2000 не тормозит. И Chrome — тоже. И даже MPC не лагает, представьте себе!

                                                            А мне жаль вашу сестру. Пользоваться морально устаревшим софтом и хромом в одну-две вкладочки — тот ещё экспериенс… И да, про MPC не надо мне рассказывать. На Athlon XP 2100+ он тормозил на XP-шке при толстых видяхах, с чего он на более слабом Atom'е-то будет летать? Или вы только хардварно-декодируемое видео смотрите?

                                                            > Давайте не переводить стрелки, а?
                                                            Исходный тезис был прост: Java == неумеренное потребление ресурсов — в первую очередь памяти, но и CPU тоже.
                                                            Этот тезис вашими рассказами про «много функционала» ничуть не опровергается. Скорее наоборот.

                                                            Ути-пути. Вы на всех наезжаете, а на вас даже не дыши? Впрочем, если вы приняли питекантропов на свой счёт — поздравляю, вы лузер. Потому что я специально переписал первый вариант, в котором хотел пройтись по вам, на нейтральный, в котором я поминаю сильно «устаревших» (они бы хоть кнпоку смогли нажать?) персонажей. И да, исходный тезис «Java тормозит». Про память там ни слова. И с памятью, согласен, Java в 1.5-3 раза более прожорливая, чем C. Но если дефицит памяти специально не создавать (повышая объём съедаемого GC времени работы) — java имеют сравнимую с c++ производительность на многих классах задач.

                                                            > Кто вам сказал, что я не использую Vim?
                                                            > Когда как. IDEA я тоже иногда использую (правда реже, чем тот же Vim).

                                                            Кхм… так и напрашиваются слова про диагноз… Хотя тут я скорее всего не прав — вы же не на managed языках пишете? На каком-нибудь с++?

                                                            > И никакие рассказы про «много функционала» этого не изменят. Да и вообще, мы статья обсуждаем про что? Про то, что «JIT-компилятор оптимизирует не круто, а очень круто»! Ну и хде? Хде эта оптимизация? Почему нам опять поют песни про функционал, а не про то, что это позволяет встроить Java в систему управления холодильников за три с половиной цента?

                                                            Где? Ну вот возьмите свою банковскую карту — не исключено, что она используется https://ru.wikipedia.org/wiki/Java_Card. Это если говорить про оптимизацию по памяти, о которой вы вдруг посреди спора вспомнили. Стандартная версия Java плохо подходит для embedded устройств. Да и потребности в этом мало. Впрочем бывают исключения из данной ситуации — https://en.wikipedia.org/wiki/Blu-ray#Java_software_interface

                                                            Если же говорить о производительности (с чего и начался весь срач «Java тормозит») — то современная Java при достаточных ресурсах по памяти, ещё раз повторюсь, мало отличается по производительности от c++.
                                                            А про функционал вспомнили, когда вы начали припоминать динозавров, утверждая, что они не тормозят.
                                                            И вы свои квадранты забыли разбить по третьему вектору — требованиям к производительности железа. Это не ресурсы (память).
                                                              0
                                                              Ну а конкретную размерность я уже не помню.
                                                              Если не помните — то зачем выступаете?

                                                              По Win95 — извините, но она сама жрёт минимум те самые 16 мегабайт — без свапа вы на 32х метрах очень мало что запустите… и покрашитесь с невозможность аллоцировать память.
                                                              Вот только не надо грязи. Windows нормально работает в 16MiB. Вот на машинках с 8MiB, которые нам как-то поставили — да, туго было, там только Windows 3.x нормально ходила. А на 32MiB уже можно и Windows98 поставить (да-да, с позиций современного дня у них «почти одинаковые требования… то есть очень мало» — а на практике Windows98 сжирала, за счёт интеграции Active Desktopа почти вдвое больше памяти).

                                                              Оно не смогло бы не тормозить.
                                                              Вот прямо даже так? А вам напомнить что Visual Studio 6 — это 1998й год? Год, когда Pentium MMX — это была норма (Pentium II только-только появился и мало у кого был), а 64MiB памяти — максимум, который поддерживал славный 430TX? Или вы хотите сказать, что тогда прям у всех разработчиков стояла самая топовая конфигурация, какая тогда была возможна?

                                                              На той вашей сестринской «печатной машинке» какая ОС?
                                                              Windows XP, однако. Зачем там больше?

                                                              Тому же Idea очень хочется скушать около гига. И начинается та же свистопляска со свапом… И это, по вашему, java виновата?
                                                              Вы же сами вроде ответили:
                                                              Ну а в отличие от производительности — с памятью вопросов нет, Java действительно её любит.
                                                              Да, конечно Java виновата — тут даже вопросов нет. Заметьте, что «скушать около гига» — это изрядная нагрузка и на процессор, не только на память, байтики не сами прыгают…

                                                              Ну и на Intel Atom c 2мя гигами оперативы… у меня вот в такой конфигурации браузеры тоже только в путь тормозят…
                                                              С выключенным JavaScript'ом и вырезанным CSS? Позвольте мне не поверить…

                                                              Они, видимо, тоже на managed языках написаны, да?
                                                              Увы. В современных браузерах изрядная часть функционала написана на языке который, похоже, существует для того, чтобы в ответ на «но хуже Java быть уже ничего не может, ведь так» «оптимистично» ответить «нет — может, ещё как может».

                                                              На Athlon XP 2100+ он тормозил на XP-шке при толстых видяхах, с чего он на более слабом Atom'е-то будет летать? Или вы только хардварно-декодируемое видео смотрите?
                                                              Вот давайте не путать божий дар с яичницей. Понятно, что если вы в видеопроигрыватель засунете 4K видео, которые процессор физически не может переварить — то тут уже ничего не сделать. Я про интерфейс. Когда я смотрю видео на этой самой «печатной машинке» — да, оно может дёргаться и замирать. Но перемотка — работает без «залипаний», выход в меню — тоже не тормозит. И окошки нормально таскаются. А вот на телефоне со сравнимой конфигурацией — я наблюдаю именно такой «фан и экспириенс»: постоянные «лаги» и «залипания». Во многом — потому что Java сжирает все ресурсы, а 10x запаса по мощности, чтобы это скомпенсировать у телефона нет.

                                                              Ненешние флагманы, впрочем, наконец-то решили эту проблему — грубой силой: четырёх-восьмиядерные процессоры и гигабайты памяти.

                                                              Ну вот возьмите свою банковскую карту — не исключено, что она используется https://ru.wikipedia.org/wiki/Java_Card
                                                              Как же вы любите «лезть в бутылку».

                                                              Вы по своей ссылке-то ходили нет? Цитирую: многие возможности языка Java не поддерживаются в Java Card, например, типы char, double, float и long, ключевое слово transient, перечислимые типы (enum), многомерные массивы, финализаторы, клонирование объектов, потоки.

                                                              На практике — всё ещё хуже, Wikipedia недоговаривает. Я-то с этой платформой работал, а вы — сюдя по тому, что на это позорище ссылаетесь — нет. Финалайзеров там нет потому что работы с динамической памятью там нет в принципе. В резльтате получаем чудо-юдо, где все массивы и объекты — глобальные (удалять их нельзя никак, а время жизнь кардлета начинается не тогда, когда вы карточку в банкомат засовываете, а когда вы оный кардлет прошиваете — кончается, соответственно, когда его удаляют), никакие Java-библиотеки использовать нельзя (много вы знаете библиотек, не создающих никаких объектов за всё время своей жизни?).

                                                              Какое отношением это поделие вообще отшение имеет к Java? Если смотреть на него с инженерной, а не маркетинговой, точки зрения?

                                                              Если же говорить о производительности (с чего и начался весь срач «Java тормозит») — то современная Java при достаточных ресурсах по памяти, ещё раз повторюсь, мало отличается по производительности от c++.
                                                              Мало отличается — это, по вашему, во сколько раз медленнее? В два раза? В десять? Ну если подобное отличие для вас ерунда — то да, наверное. А я таки руководствуюсь мнением Кнута (да-да, того самого, который изрёк знаменитое изречение, которое очень любят цитировать любители Java, про «преждемвременную оптимизацию»): «В устроявшихся инжинерных дисциплинах улучшение на 12%, достижимое без черезмерных затрат, никогда не считается несущественным и я верю что такая же точка зрения должна быть применена в программировании» (Knuth, Donald (December 1974). «Structured Programming with go to Statements». ACM Computing Surveys 6 (4): 268.)

                                                              И, как я уже сказал, я пока не видел ничего, написанного на Java, что укладывалось бы в эти 12%.
                                                                0
                                                                > Вот только не надо грязи. Windows нормально работает в 16MiB. Вот на машинках с 8MiB, которые нам как-то поставили — да, туго было, там только Windows 3.x нормально ходила. А на 32MiB уже можно и Windows98 поставить (да-да, с позиций современного дня у них «почти одинаковые требования… то есть очень мало» — а на практике Windows98 сжирала, за счёт интеграции Active Desktopа почти вдвое больше памяти).

                                                                На моей практике на 8Мб W95 вообще не завелась. На 12ти — да. Кстати устанавливалась 6 часов… Intel80386DX + сопр. Можно я буду его тормозом называть за это? Нет? А почему? Вы же Java называете тормозом, не давая ей достаточно ресурсов.

                                                                > Вот прямо даже так? А вам напомнить что Visual Studio 6 — это 1998й год? Год, когда Pentium MMX — это была норма (Pentium II только-только появился и мало у кого был), а 64MiB памяти — максимум, который поддерживал славный 430TX? Или вы хотите сказать, что тогда прям у всех разработчиков стояла самая топовая конфигурация, какая тогда была возможна?

                                                                И вы прям помните, как на 32ти метрах оно летало? И вот ну совсем не тормозило? Извините, но у меня страшное подозрение, что вы лукавите. Впрочем, если это было единственное приложение и достаточно мелкий проект — возможно так и было.

                                                                > Windows XP, однако. Зачем там больше?

                                                                Ради обновлений безопасности? Ради совместимости с современным железом (внешние устройства)? Ради совместимости с современным ПО? (Хотя с такой конфигурацией последний вопрос не самый актуальный… это действительно печатная машинка, незачем туда ПО ставить).

                                                                > Да, конечно Java виновата — тут даже вопросов нет. Заметьте, что «скушать около гига» — это изрядная нагрузка и на процессор, не только на память, байтики не сами прыгают…

                                                                Если память не дико фрагментированная — хрен там, а не изрядная нагрузка на процессор. Java аллоцирует под себя память максимально доступными блоками (т.е. будет доступно подряд гиг и ей он будет нужен — она его целиком и сожрёт). Да и это накладные расходы запуска приложения, а не его работы.
                                                                И заметьте, если вы не соблюдаете блок «системные требования», то виновато не ПО, которое тормозит/падает, а вы. Надо это чётко понимать.

                                                                > С выключенным JavaScript'ом и вырезанным CSS? Позвольте мне не поверить…

                                                                Позвольте мне спросить — зачем вам браузер?

                                                                > Увы. В современных браузерах изрядная часть функционала написана на языке который, похоже, существует для того, чтобы в ответ на «но хуже Java быть уже ничего не может, ведь так» «оптимистично» ответить «нет — может, ещё как может».

                                                                Позвольте мне не согласиться. JS хоть и имеет множество косяков — остаётся вполне вменяемым языком, на котором можно сделать любой web-UI. Заметьте, всё более «эффективное» почему-то мрёт в вебе. Поэтому называть его плохим языком — я бы не спешил.

                                                                > Как же вы любите «лезть в бутылку».

                                                                Не больше, чем вы.

                                                                > Какое отношением это поделие вообще отшение имеет к Java? Если смотреть на него с инженерной, а не маркетинговой, точки зрения?

                                                                Не поверите — вы мне не сообщили ровным счётом ничего нового. А поделие это — подмножество языка, эффективно работающее с памятью. Как вы и хотели.

                                                                > Мало отличается — это, по вашему, во сколько раз медленнее? В два раза? В десять? Ну если подобное отличие для вас ерунда — то да, наверное. А я таки руководствуюсь мнением Кнута (да-да, того самого, который изрёк знаменитое изречение, которое очень любят цитировать любители Java, про «преждемвременную оптимизацию»): «В устроявшихся инжинерных дисциплинах улучшение на 12%, достижимое без черезмерных затрат, никогда не считается несущественным и я верю что такая же точка зрения должна быть применена в программировании» (Knuth, Donald (December 1974). «Structured Programming with go to Statements». ACM Computing Surveys 6 (4): 268.)

                                                                Мало отличается — это мало отличается. На уровне плюс-минус десять процентов. И я не руководствуюсь ничьим мнением. Но вот согласно мнению вами любимого Кнута — Java использовать стоит. Т.к. улучшение сильно больше 12% — время разработки (по сравнению с c++) сокращается в 2-3 раза. Вы просто вбили себе в голову, что java тормозная… но ведь нет! Она может решать некоторые классы задач на вполне нормальной скорости. Инженерная аналогия — стоит ли строить мост в 4 полосы за n+m денег (стройка + инженерные расчёты) и t времени или лучше построить 2 двухполосных моста за n+m*2/3 денег, каждый из которых можно построить за t/3 времени? По сути в этой аналогии достигается экономия на расчётах (проще и частично перекликаются), экономия на времени (можно одновременно строить) и потенциальная инфраструктурная плюшка — легче развязывать потоки машин + легче обслуживать (в крайнем случае один мост можно временно закрыть).

                                                                > И, как я уже сказал, я пока не видел ничего, написанного на Java, что укладывалось бы в эти 12%.

                                                                А я видел мало тормозящих Java-программ. И много — не тормозящих. И в большинстве случаев тормоза случались на слабых по объёму памяти машинах.
                                                                  0
                                                                  На моей практике на 8Мб W95 вообще не завелась. На 12ти — да. Кстати устанавливалась 6 часов… Intel80386DX + сопр. Можно я буду его тормозом называть за это?
                                                                  Да, конечно — по сравнению с Windows 3.x это был монстр и тормоз. Но на 8MiB он таки заводился — если у вас этого не получилось то это скорее говорит о кривых руках, чем о тормознутости Windows 95. Официальные требования вообще о 4M говорят. Вы точно уверены, что вас память не подводит и это была Windows 95, не Windows 95 OSR2 (реально требовавшая уже 8MiB) или Windows 98 (которой было нужно ажно 16MiB)?

                                                                  Нет? А почему?
                                                                  В том-то и дело, что нипочему. Я — человек простой и называю чёрное чёрным, а белое — белым, представьте себе. Windows95 — это очень тяжёлая операционка, если сравнить её, скажем, с Windows 3.x (Windows 3.0 вполне ходила на 1MiB, хотя для Windows 3.1 этого, уже, в общем, стало не хватать — официальные требования не врут) — но вполне себе лёгкая, если сравнивать её с Windows NT (эта вообще каких-то космических ресурсов требовала). Не очень понятно, почему вы считаете, что я буду это отрицать.

                                                                  В обоих случаях известно за что вы платите: в случае с Windows 95 — за возможность написания 32-битных многопоточных программ (ну и за красивые кнопочки, конечно, но красивые кнопочки и в Windows 3.x можно было нарисовать, в общем-то), в Windows NT — за возможность изолировать программы друг от друга (с некоторыми оговорками, правда, ради скорости и уменьшения потребления ресурсов Windows NT 4.0 сделала большой шаг назад).

                                                                  Хотите ли вы за эти красивости платить повышенными требования к железу — решать вам, но назвать их «незначительно отличающимися» я не могу: даже требования Windows 95 и Windows 98 прилично отличаются друг от друга (официальные, кстати — тоже), а Windows NT — так вообще тормоз…

                                                                  То же самое и с Java: да, я знаю, что она позволяет использовать труд условных «неквалифицированных индусов» и тем самым ускорить разработку. Но от этого она не перестаёт быть тормозным, тяжёлым, монстром. Это просто разные вещи, не нужно их в одну кучу валить.
                                                                    +1
                                                                    > Да, конечно — по сравнению с Windows 3.x это был монстр и тормоз. Но на 8MiB он таки заводился — если у вас этого не получилось то это скорее говорит о кривых руках, чем о тормознутости Windows 95. Официальные требования вообще о 4M говорят. Вы точно уверены, что вас память не подводит и это была Windows 95, не Windows 95 OSR2 (реально требовавшая уже 8MiB) или Windows 98 (которой было нужно ажно 16MiB)?

                                                                    За редакцию не скажу (хотя никаких дополнительных символов после «95» я в названии не видел). Но точно 95. 98ая на 386 как-то не хотела устанавливаться.

                                                                    > В том-то и дело, что нипочему. Я — человек простой и называю чёрное чёрным, а белое — белым, представьте себе. Windows95 — это очень тяжёлая операционка, если сравнить её, скажем, с Windows 3.x (Windows 3.0 вполне ходила на 1MiB, хотя для Windows 3.1 этого, уже, в общем, стало не хватать — официальные требования не врут) — но вполне себе лёгкая, если сравнивать её с Windows NT (эта вообще каких-то космических ресурсов требовала). Не очень понятно, почему вы считаете, что я буду это отрицать.

                                                                    Да вы не «простой человек» и не «называете чёрное чёрным». Вы действуете как фанатик. И машину окрашенную с одной стороны чёрным, а с другой — почти белым называете чёрной. И из-за своего отношения (а не реальных проблем языка и платформы) вы упорно не хотите слушать оппонентов, измором пытаетес всех убедить, что «java тормозит», передёргиваете слова (был спор о производительности, вы откуда-то вытащили потребление памяти)… Вот поэтому я и считаю, что вы будете отрицать.

                                                                    > Хотите ли вы за эти красивости платить повышенными требования к железу — решать вам, но назвать их «незначительно отличающимися» я не могу: даже требования Windows 95 и Windows 98 прилично отличаются друг от друга (официальные, кстати — тоже), а Windows NT — так вообще тормоз…

                                                                    Заметьте, вы ни разу не сказали «тормоза» по отношению к W95. А ведь там та же ситуация — за большие возможности приходится платить большим потреблением. Только Java при достатке памяти на многих классах (специально для отмечаю — не на всех! НО на многих!) задач имеет производительность сравнимую с c++.

                                                                    > То же самое и с Java: да, я знаю, что она позволяет использовать труд условных «неквалифицированных индусов» и тем самым ускорить разработку. Но от этого она не перестаёт быть тормозным, тяжёлым, монстром. Это просто разные вещи, не нужно их в одну кучу валить.

                                                                    Да плевать на индусов. В c++ они тоже работают. И драйверы на C пишут. Причём тут индусы вообще? Речь именно об ускорении разработки при получении сравнимой производительности… платить приходится объёмами памяти — да. И если вы назовёте её тяжёлым монстром — никто не возмутится. Если вы скажете, что на каких-то классах задач она тормоз — тоже все промолчат. А вот общая классификация как «тормозной тяжёлый монстр» — это извините, наглая ложь. И вы фанатично(!) пытаетесь это сказать (даже не доказать). Кстати, в соседнеё теме про планируемые изменения в c++ вас тоже легко узнавать по горячности и абсолютности утверждений.
                                                +3
                                                Разработчику не жалко потратить десятки а иногда сотни тактов процессора чтобы избежать лишнего доступа в кеши процессора или в оперативку.
                                                А давайте не обобщённо «десятки и сотни», а более предметно. Возьмём данные отсюда (они, правда, немного устарели, но порядок величин показывают верно): L1 — 3-4 тактов, L2 — 10-15 тактов, доступ в память — ~200 циклов (на серверных процессорах есть ещё L3 — он где-то посередине).

                                                То есть: память — это сотни тактов, L2-L3 — десятки, L1 — единицы.

                                                А теперь фокус: байткод и интерпретатор зачастую вместе занимают меньше места чем соответствующий ассемблер.
                                                Это ни разу не фокус, этим пользовались ещё разработчики Excel'я в далёком 1985м году, чтобы уместить своё творение на минимальное число дискет. Размер — это действительно экономит. А вот получить этого выигрыш в скорости — штука «посильнее „Фауста“ Гете».

                                                Кеш L1 (самый важный) — он маленький. По нынешним меркам — просто крошечный. PowerPC 1991 года — 16K, Pentium MMX 1997 года — 32K, но даже в самом современном Skylake — всего лишь 64K, увы. Вы серьёзно хотите сказать что у вас туда уместится и приложение и JIT и скомпилированный код? Который при этом ещё и будет быстрее того, что породил компилятор C++?

                                                Достигается это тем что JVM байт-код это хорошо упакованные высокоуровневые инструкции, которым могут соответствовать десятки команд ассемблера.
                                                Правильно. Но есть одна проблеммка: интерпретировать его долго, мы тут не зря JIT'ы обсуждаем. А вот скомпилированный JIT'ом код — это не только, собственно, вычисления, но ещё и дополнительные проверки и логика на случай «изменения направлений движения» и прочее. И занимает этот код больше, чем то, что породил C++. Ненамного, но больше. А ваш этот суперлаконичный код где-то сидит — это тоже сверх того кода, который нужно, собственно, исполнить.

                                                Вот так и получается что действия, которые выполняются относительно редко (95% всей логики), логично интерпретировать.
                                                Потому что скорость работы этого кода ни на что не влияет — да, именно так. Это и в программах на C++ так и в Java и где угодно. Но это не очень важно — важна скорость работы «горячего» кода.

                                                Готов поспорить что если гипотетически скомпилировать ее в машинные команды (реально не получится ибо рефлекшн), то эти 5-20 минут разогрева потратятся просто на загрузку разбухшего кода в память и прогрев кешей.
                                                А это — уже от архитектуры приложений зависит. Chrome имеет сравнимое количество кода — но «прогреваться» после запуска ему не нужно.

                                                Да и вообще — вы просто посчитайте. Даже очень плохонький винчестер даёт скорость загрузки порядка 5-10MiB в секунду при дикой фрагментации диска. Вы всерьёз хотите сказать, что у вас Idea загружает в себя несколько гигабайт кода?

                                                В общем JIT и Java — это такой «путь китайского комсомола»: сначала насоздаём себе трудностей, а потом будем героически их преодолевать.

                                                Достижения JIT'остроителей впечатляют, да, но не следует забывать что все усилия их разработчиков привели лишь к тому, что мы получили скорость «почти такую же как при использовании технологий 30-летней давности».

                                                Такой себе Space Shuttle: то, что летает — это чудо, это реально офигительный подвиг, разработчики сотворили почти немыслимое. А вот то, что это чудо вообще кто-то задумал, не то, что реализовал — это ошибка. Большая ошибка.
                                                  0
                                                  > на серверных процессорах есть ещё L3 — он где-то посередине
                                                  L3 уже давно пришёл на десктопы. У меня его 6МБ, и мой процессор далеко не топовый и современный.
                                            –7
                                            А они и работают быстро. Отстают от С++ в 1.5...2 раза: http://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=java&lang2=gpp
                                              +15
                                              Сходил я по вашей ссылке, посмотрел. Ясное дело, не все.
                                              Посмотрел я мандельброт. Ну что сказать, автор некорректно написал java-код — и поэтому, предположительно, поймал на нем эффект частой миграции данных между кэшами (в данном случае — это true sharing). Конкретно проблемы с этой строчкой: while((y=yCt.getAndIncrement())<out.length) Вы представьте: каждое getAndIncrement() должно подтянуть кэшлайн с новым значением себе. Ясное дело — это около out.length кэш-промахов. Причем, там тяжелый случай кэш-промаха, предположительно. В отличии от OMP, которое разделило диапазоны до старта цикла.
                                              Ну и плюс, запущено без прогрева. Никто не обещал, что до прогрева оно будет летать.
                                              Ну и плюс автор вывод c++ направил в файл (по крайней мере, возможность предусмотрел — третьим параметром идет имя файла), а вывод java направил в консоль. Консоль — штука не очень быстрая и непредсказуемо-тормозная, так что он померял в итоге непонятно что. Естественно, я его тест переписал, направив и java тоже в файл. по-сути, заенил одну строчку на: OutputStream stream = new java.io.FileOutputStream(«xyz»);

                                              Результаты:

                                              # time java -server -XX:+TieredCompilation -XX:+AggressiveOpts Mandelbrot 16000 xyz

                                              real 0m6.211s
                                              user 0m22.394s
                                              sys 0m0.117s

                                              (^^^^это i586 версия)

                                              # time /usr/local/jdk1.8.0_91/bin/java -server -XX:+TieredCompilation -XX:+AggressiveOpts Mandelbrot 16000 xyz

                                              real 0m5.774s
                                              user 0m20.944s
                                              sys 0m0.151s

                                              (^^^^ это x64)

                                              # time ./mandelbrot.gpp-9.gpp_run 16000 xyz

                                              real 0m7.330s
                                              user 0m27.380s
                                              sys 0m0.039s

                                              и это результат когда java с атомиками работает. Если переписать без них — можно добиться еще большего. Это на amd, кстати.
                                                +7
                                                проба этого же теста на Intel® Core(TM)2 CPU E7500 @ 2.93GHz
                                                На компе стоит i586 операционка, поэтому OMP версию пришлось перекомпилить с ключиком -m32. Так же, java там 1.8.0_51 (тоже i586, ясное дело), обновляться до 1.8.0_92 было влом.
                                                Результаты:

                                                # /tmp/3$ time ./mandelbrot.gpp-9.gpp_run 16000 xyz

                                                real 0m31.277s
                                                user 1m1.756s
                                                sys 0m0.132s

                                                # time java -server -XX:+TieredCompilation -XX:+AggressiveOpts Mandelbrot 16000 xyz

                                                real 0m27.763s
                                                user 0m54.036s
                                                sys 0m0.300s
                                                  +7

                                                  Интересно, зачем вы с -XX:+AggressiveOpts запускаете? Это сознательный выбор или просто вам кто-то когда-то сказал, что так что-то будет быстрее?


                                                  На 64-бит -server и -XX:+TieredCompilation работает по дефолту, а -client вообще игнорируется.

                                                    +1
                                                    Да.
                                                    Я — не использую, использовал автор исходников. Там строка запуска (а в случае с++ версии — строка запуска компилятора тоже) под исходником находится. Было 2 ночи, собирался спать, думал по-минимуму — копипастил по-макимуму.

                                                    Наверное, если бы результат вышел плохой, это заставило бы задуматься и что-то сделать, но результат оказался хорошим — и я на этом остановился.
                                                      +3

                                                      В вашем случае -XX:+AggressiveOpts скорее всего ни на что не влияет. Просто это довольно дурная опция. В разных версиях JVM она может включать разные штуки, которые не всегда нужны (не зря же они выключены по дефолту). Поэтому не стоит пользоваться ей слепо, не зная, что конкретно она включает в вашей JVM и нужно ли это вам.

                                                    +2
                                                    > Ну что сказать, автор некорректно написал java-код

                                                    benchmarksgame.alioth.debian.org/play.html#contribute

                                                    > Ну и плюс, запущено без прогрева. Никто не обещал, что до прогрева оно будет летать.

                                                    benchmarksgame.alioth.debian.org/sometimes-people-just-make-up-stuff.html#jvm-startup-time

                                                    > Консоль — штука не очень быстрая и непредсказуемо-тормозная, так что он померял в итоге непонятно что.

                                                    /dev/null

                                                    benchmarksgame.alioth.debian.org/how-programs-are-measured.html
                                                      +4
                                                      Нет, писать ему багрепорты и править его код я не стану. Это вы ему отправляйте ссылку на хабр, пускай читает критику и правит.

                                                      в любом случае, у меня результаты получаются не такие, как у него.
                                                      Сейчас попробовал его fannkuch-redux (java тоже некорректно написана), запускал раз 10 оба примера. Вердикт — они по времени работают одинаково, 11...12сек, и я бы не сказал, что имеется перевес в чью-то пользу. Наверное, можно было бы усреднить и получить результат, но нет смысла. т.к. все равно в java версии использованы атомики, а плюсовая разделена на независимые треды заранее. т.е. сравнение некорректно.

                                                      Не знаю, почему он получил видимую разницу. У него старое железо(«q6600 — проц для широких масс вдвое дешевле» — гугл), а такое железо как раз плохо может работать при конкурентном доступе к данным — то есть как раз с атомиками. Наверное, поэтому. Скорей всего, если написать тесты одинаково, то разница была бы в пределах погрешности.
                                                        +3
                                                        Судя по тексту ответа он и написан автором Benchmark Game.
                                                        А вообще забавно, конечно — как только в интернетах начинают обсуждать Benchmark Game, его автор сразу же появляется в комментариях. Как он это делает — ума не приложу :)
                                                          +1
                                                          > Как он это делает — ума не приложу :)

                                                          :-)

                                                          https://www.google.com/search?q=benchmarksgame#q=benchmarksgame&tbs=qdr:d
                                                            0
                                                            Ahaha! Welcome to Soviet Russia, Isaac :)
                                                            Now you'll have to learn russian for the sake of comfortable discussion :)
                                                              0
                                                              Спасибо!
                                                  +3
                                                  Скорее проблема в том, что Java в начале «тормозит», и во время разработки программы обычно до срабатывания JIT дело не доходит. То есть, разработчики привыкают к тому, что их программы «тормозят». Потом добавляют какую-нибудь сложную бизнес-логику, кучу SQL-запросов и т.д. Во время разработки, поскольку всё итак тормозит, проблема обычно не заметна. А когда выкладывают на продакшен, то оказывается, что JIT программу особо не ускоряет, потому что она не проектировалась с фокусом на скорость.
                                                  То есть, несмотря на то, что в теории программы должны быть быстрые, по факту они бывают достаточно быстрыми только в определенных случаях (например, игры обычно неплохо оптимизированы, или тот же Hadoop).
                                                  +3
                                                  Про магию JVM лучше всего слушать Шипилева, рекомендую например вот это: https://youtu.be/nHiEKXpG_4M
                                                  Примерно в середине доклада вроде рассказывает про спекуляции с виртуальными методами тоже (тема статьи)
                                                    +7

                                                    Я думаю, что lany – выбор не хуже в данном случае.

                                                      +6

                                                      Ну в вопросах производительности JVM мне до Performance Tsar, конечно, очень далеко. Но он же не может написать все статьи на эту тему, поэтому иногда пишут другие люди :-) Шипилёв читал черновик этой статьи, сильно не придирался :-)

                                                    +1
                                                    Нету простых ответов, типа «быстрее в полтора раза», «медленнее в два» и т.п. Есть сценарии, которых бесконечно много, но можно выделить основные, типа «векторная математика, графика, работа с бд», и так далее.

                                                    Читайте и смотрите классику: вот свежий часовой доклад от человека, который задизайнил JIT компилятор хотспота в свое время: https://www.infoq.com/presentations/java-vs-c-performance
                                                      +8
                                                      Есть сценарии, которых бесконечно много, но можно выделить основные, типа «векторная математика, графика, работа с бд», и так далее.
                                                      Сценариев, конечно, «бесконечно много», но, в общем, их не так сложно рассклассифицировать.

                                                      Начать нужно с конца. Работать всем нашим сценариям предстоит, представьте себе, на CPU. А у CPU есть кеш. 64K, как говорит нам Wikipedia. Который либо поступает в распоряжение программы, либо делится между JIT'ом и программой.

                                                      То есть если у нас программа имеет статический профиль (а «суперчудеса» все JIT'ы демонстрируют на статическом профиле), то удел JIT'а — получить результат чуть хуже, чем у приличного статического компилятора. Если же в программе типов много и они меняются часто, то скорость всего хозяйства получается — «ниже плинтуса».

                                                      То есть хотя теоретически JIT и может выиграть у компилятора C++, но происходит это примерно так же часто, как солнечные затмения: хорошо если раз за свою жизнь увидите. Можно, конечно, сесть на самолёт и слетать куда-нибудь… тогда чаще. Так часто бенчмарки делают: смотрим на 100500 задач, отбираем парочку где наш JIT особо хорош… вуаля: есть статья. Но если вам нужна не статья в журнал, а программа, то увы: на практике вы этих чудес не увидите.

                                                      Тем не менее современные JIT'ы уже дошли, наконец, до состояния, когда вся эта конструкция (убогий, безумно тормозной, байткод — плюс JIT, который призван всё это компенсировать) неплохо работает. При двух непременных условиях, впрочем:
                                                      1. Вы должны работать с данными без всякого полиморфизма (иначе JIT не сможет «развернуться»).
                                                      2. Вы должны не забывать о том, что если вам нужно загрузить и обработать гигабайт-другой данных, то ваш сервер неплохо бы оснастить несколькими гигабайтами памяти — примерно так втрое больше, чем вам реально нужно. А иначе вам GC всю малину испортит.
                                                      2a. Есть, правда, выход: вывести GC «за скобки». Выделить столько массивов простых типов, сколько вам нужно, работать там со смещениями — и вуаля: скорость примерно как у C/C++! Вот только зачем вам при таком подхое Java вообще? Понятно, конечно, что настоящий программист программист может писать фортрановские программы на любом языке… но зачем? Пишите фортрановские программы на фортране — и да пребудет с вами сила!
                                                        +5
                                                        у CPU есть кеш. 64K, как говорит нам Wikipedia. Который либо поступает в распоряжение программы, либо делится между JIT'ом и программой.


                                                        JIT не работает долго на прогретой программе (а джавы сереверные программы работают часто неделями). Реальный профиль работы CPU примерно как на слайде 23 вот этой презентации: http://www.slideshare.net/ZeroTurnaround/vladimir-ivanovjvmjitcompilationoverview-24613146 GC — да — кушает процессор — особенно concurrent, это плата на managed свойства языка, как спору AOT-JIT почти не имеет отношения.

                                                        То есть если у нас программа имеет статический профиль (а «суперчудеса» все JIT'ы демонстрируют на статическом профиле)


                                                        Ровно наоборот. Как раз статический профиль можно через PGO механизмы подать в gcc/clang и получить идеальный профиль. JIT способен отработать изменения поведения программы и рекомпелироваться. Например, если код, который был прогрет и нормально работал, вдруг начинает бросать exceptions. Кроме того, JVM перемещает скомпелированный код, что позволяет часто взаимодействующему коду находиться вместе, сокращая TLB misses. Наконец, уникальная возможность — можно прицепиться к программе, могда метод с брейкпоинтом уйдет в интерпретатор, после отключения bp обратно рекомпелируется,

                                                        1. Вы должны работать с данными без всякого полиморфизма (иначе JIT не сможет «развернуться»).


                                                        С умеренным полиморфизмом (а это 2-3 имплементора виртуальной функции) JIT справится, а не хуже AOTа, дальше — беда, как правило — для всех.

                                                        ваш сервер неплохо бы оснастить несколькими гигабайтами памяти — примерно так втрое больше, чем вам реально нужно


                                                        Это почти справедливо, но это расходы GC, а не JITа. Это другая тема. Я плохо знаком с .NЕT миром, но там есть AOT + GC. Всё тоже самое с точки зрения расхода памяти. И да, не втрое, а примерно +30% для долгоживущих объектов и в 2 раза для «молодого поколения». Это длинная тема.

                                                        Есть, правда, выход: вывести GC «за скобки». Выделить столько массивов простых типов, сколько вам нужно, работать там со смещениями — и вуаля: скорость примерно как у C/C++


                                                        Это справедливо. Работа со структурами, с массивами структур, с вложенными массивами — самое слабое место Java. Ждём десятку — arrays 2.0, value types и и.п. Но к JIT это не имеет отношения, это слабость языка. JIT в .NET прекрасно работает с массивами структур.

                                                        Есть еще одно слабое место именно JIT-a — это автовекторизация. JIT может найти возможность использовать векторные инструкции в простых паттернах, как и GCC/clang, но легко соорудить пример, с которыми ни один компилятор не справится, оптимизация «вручную» победит. AES шифрование например (по этой причине шифрование и хэширование делается интринсиками, а не компилятором).
                                                          +1
                                                          Ещё раз прочитайте что вы написали
                                                          JIT не работает долго на прогретой программе (а джавы сереверные программы работают часто неделями)
                                                          JIT способен отработать изменения поведения программы и рекомпелироваться"
                                                          . Либо первое, либо второе, а одноверменно — примерно как наступление солнечного затемения.

                                                          Да, если у вас паттерн использования резко сменился (скажем если к вам вместо обычных запросов вдруг начали посылать один, весьма специфический, в надежде вас за'DDOS'ить), то вы можете что-то отыграть — но как часто это случается?

                                                          Это почти справедливо, но это расходы GC, а не JITа. Это другая тема.
                                                          Это та же тема: «великораспильные языки» против «старой школы».

                                                          Объясняю свою позицию: когда-то давно, много лет назад, когда IBM PC 4.77MHz уже немного устаревала, но для школы годилась я столкнулся с «типа крутым редактором» (интересно — как он назывался? сейчас уже не вспомнить, но помню что там были разные фишки типа спеллчекера). И была у него одна проблема: на большинстве машин в классе со 256KiB он не работал, требовал «полных» 640KiB. А ещё он осталавливался на полсекунды каждые примерно секунд пять. На вопрос в духе «а почему собственно» поступил ответ в духе «ту эта, у нас тут немного больше памяти требуется, а ещё задержки от сборщика мусора и байткода — но вы не волнуйтесь, скоро мы всё починим». С тех пор идут годы — и заклинание «вы не волнуйтесь, скоро мы всё починим» в отношении managed языков не меняется. Почему я всю эту конструкцию считаю шарлатанством и выкидыванием денег не ветер.

                                                          P.S. Есть ещё второй подобный пример, кстати. Когда C++ (и STL) только появились, то многие высказывали недовольство тем, как там сделано метапрограммирование: вместо того, чтобы дать возможность программисту точно описать — чего он, собственно, хочет в C++ принято порождать программы, которые, если компилировать их без оптимизации, «в лоб», будут порождать терабайты кода — в надежде на то, что компилятор всё «подчистит». И там, тоже, до сих пор это аукается. Я принимаю и Java и C++ (свои задачи они, в общем, решают — хоть и с оговорками), хотя меня до сих пор терзает вопрос: а если бы все миллиарды, которые мы вбухали в попытку (частично успешную) обойти проблемы, которые мы же сами себе и создали — как бы изменится мир? Теперь уже не узнать…

                                                          AES шифрование например (по этой причине шифрование и хэширование делается интринсиками, а не компилятором).
                                                          Там слишком сложный паттерн, чтобы его мог хоть один компилятор в мире распознать и в AES-NI завернуть. Автовекторизация в JIT'ах пока слабее, чем clang'е или gcc — но это, я думаю, временно. Ничего смертельно сложного там нет.

                                                          Работа со структурами, с массивами структур, с вложенными массивами — самое слабое место Java. Ждём десятку — arrays 2.0, value types и и.п. Но к JIT это не имеет отношения, это слабость языка.
                                                          А я, в общем, и обсуждаю в основном язык.

                                                          JIT, это знаменитое:
                                                          Один пришивает карман, один — проймочку, я лично пришиваю пуговицы. К пуговицам претензии есть?
                                                          Так вот у меня претенции не к пуговицам, а к тому, что путём увеличения их размера и количества пытаются сделать носибельным фасон костюма, который, по хорошему, вообще не должен был бы использоваться!
                                                            +2
                                                            Ещё раз прочитайте что вы написали

                                                            JIT не работает долго на прогретой программе (а джавы сереверные программы работают часто неделями)

                                                            JIT способен отработать изменения поведения программы и рекомпелироваться"

                                                            . Либо первое, либо второе, а одноверменно — примерно как наступление солнечного затемения.

                                                            Да, если у вас паттерн использования резко сменился (скажем если к вам вместо обычных запросов вдруг начали посылать один, весьма специфический, в надежде вас за'DDOS'ить), то вы можете что-то отыграть — но как часто это случается?


                                                            Здесь нету противоречия. JIT стартут вместе с JVM, работает в N потоков, пока не закончится очередь CompileQueue и JVM не придет в некое стабильное прогретое состояние. Компиляция одного метода занимает доли секунд, а приложение работают, часто, неделями. Если требуется рекомпиляция, то основной проигрыш от того, что во время рекомпиляции метод интерпретируется, что на порядок медленнее, но собоственно компиляция проходит быстро и безболезненно. Я как раз готовлю доклад про деоптимизации, так вот довольно сложно даже написать такой тест, чтобы проблема была ощутимо заметна.

                                                            А я, в общем, и обсуждаю в основном язык.

                                                            Мы же обсуждаем статью «JIT-компилятор оптимизирует не круто, а очень круто»? Здесь мог бы быть любой из более чем сотни языков, которые работают на JVM. Мог бы быть даже .NET + CLR — уверен, что JIT в нем работает примерно также, при этом и «убогого байткода» там нет, и других недостатков, вроде отсутствия массивов структур и контроля для лейаутом
                                                          +4
                                                          Вы в своем рассуждении не учли:
                                                          — если профиль динамический — он (по факту, хоть и не собирается) будет динамический и на с++ тоже, поэтому глупо ждать какой-то существенной просадки «ниже плинтуса» производительности в java — но при этом считать что с++ будет по прежнему «летать».

                                                          — JIT, в отличии от «приличного статического компилятора» может компилить, используя особенности платформы, на которой работает, и за счет этого тоже что-то выигрывать.

                                                          — в 90ых было очевидно, кто тормозит. Сейчас jit компилятор хорош. По сути, g++ — это компилятор, jit — это тоже компилятор. Поэтому, сейчас эти расклады ненастолько очевидны. В jit было вкинуто очень много человеко-часов, а g++ — гнутая софтина, в которой некоторое время (4.9.0) вообще жили критичные баги и всем было пофиг. И нет возможности корректно сравнить jit и c++ на реальных проектах. Даже если сделать 1 проект на два раза на разных технологиях — решающую роль может оказать квалификация/специализация/предпочтения программиста. Поэтому, говорить «происходит это примерно так же часто, как солнечные затмения» — необоснованно. Вообще, на сегодня известен факт: в 99% случаев программа тормозит не в том месте, где думает программист.

                                                          — в моих тестах выше по каментам подход «смотрим на 100500 задач, отбираем парочку» не использовался. Надо будет по свободе провести тесты с остальными примерами автора.

                                                          — полиморфизм будет тормозным и в с++, ведь от поиска по таблице виртуальных функций не уйдешь. Принципы работы ведь одни и те же. Возможно даже плюсы будут медленней, из за множественного наследования. Более того, jit может выбросить поиск, заинлийнить — и стать быстрым. И это происходит довольно часто. Так что тут, наверное, jit.

                                                          — насчет вопроса «зачем вам при таком подхое Java вообще?» Очевидно, обработка гигабайт данных — это, в большинстве случаев, не 100% программы, а скорей 1%. java — для оставшихся 99%, которым ненужно так много памяти.

                                                          Итог: я думаю, у вас предвзятое отношение к jit, оно у вас сформировалось исторически — потому, что действительно когда-то было оправдано так считать. Но платформа развивается.

                                                          Есть еще интересное социальное явление: когда люди повторяя мантру «жава тормозит», пишут некорректный и тормозной код на плюсах. Я такое реально встречал на практике, например был у нас прецедент: json_spirit либа ела 80% проца. Перешли на java (и плюс размер данных увеличился раза в 3) — кушает 1..5%. Qt-шный json-парсер тоже, кстати, много проца ест. Не 80% конечно, но заметно больше. Так что ненадо жить представлениями 90ых. Отрасль развивается.
                                                            +1
                                                            Есть еще интересное социальное явление: когда люди повторяя мантру «жава тормозит», пишут некорректный и тормозной код на плюсах. Я такое реально встречал на практике, например был у нас прецедент: json_spirit либа ела 80% проца.
                                                            С этим спорить не буду — на C++ тоже можно «Г» написать.

                                                            Отрасль развивается.
                                                            Если бы. Отрасль ходит по кругу. Или, скорее — движется по спирали идущей вниз. Вы не поверите, но у меня есть дома вот такая машинка. И на ней — есть GUI (совершенно не тормозящий… ещё бы, целых 66Mhz), редакторы, браузер и прочее (браузер, правда, запускается небыстро, спорить не буду). И он никогда не «уходит в себя» на час! А мой X1 Carbon — уходит! Да, я знаю, AGA поддерживает, в типичном случае, 640x480x256 цветов, а мой X1 — 2560x1440x16777216. Разница в потребной памяти — 48 раз. Но, казалось бы, современные технологии должны компенсировать? Фиг вам. Вот в этом-то и беда. Не туда мы куда-то идём…
                                                              +2

                                                              Ох, опять… Вы на этих машинах одни и те же приложения запускаете? Скорее всего нет. По возможностям старые программы могут посоперничать с современными? Сомневаюсь.
                                                              Как-то глупо было бы, если железо развивалось, а софт не использовал это железо на максимум.

                                                                +1
                                                                По возможностям старые программы могут посоперничать с современными?
                                                                В том-то и дело, что могут! По бздынь-бдыщ-какие-изящные-пимпочки — не могут, а именно по возможностям — могут легко. Какой-нибудь MultiEdit по своим возможностям не сильно отстаёт от славного SlickEdit'а — хотя да, он далеко не так красив, но, чёрт побери, он работал в 640KiB! На 4.77Mhz!

                                                                Да, существуют программы, которые имеют то, чего принципиально было нельзя сделать на компьютерах 20-летней давности (хотя это ещё поискать нужно: та же Amiga телестудмиями использовалась вплоть до появления TVHD), но подавляющее большинство — требуют ресурсов на порядки (то есть не в 10 раз, а скорее в 100) больше, чем им реально нужно.

                                                                Я понимаю почему так выгодно делать с точки зрения зарабатывания денег — но только после этого не надо рассказывать после этого как у нас всё эффективно и хорошо.

                                                                Как-то глупо было бы, если железо развивалось, а софт не использовал это железо на максимум.
                                                                Ещё глупее — делать вид, что все эти JIT-ухищрения приведут хоть к какому-то выхлопу, который увидит пользователь. Нет, они просто позволят разработчикам ввести ещё парочку уровней индирекции, которые сожрут весь выигрыш…
                                                                  +2
                                                                  а именно по возможностям — могут легко

                                                                  Емакс вон тоже может и на старых тачках запускаться. Однако, голый емакс мало кого устраивает, а вот дополнения уже нагружают систему. Я сомневаюсь, что MultiEdit потянет на 640KiB и 4.77Mhz все возможности, которые я использую в своём редакторе.


                                                                  Ещё глупее — делать вид, что все эти JIT-ухищрения приведут хоть к какому-то выхлопу, который увидит пользователь.

                                                                  Ну если писать код плохо, то никакие оптимизации не спасут. И уж тем более, не стоит надеяться на JIT.
                                                                  А пример, который в статье, вполне может встретиться в реальной программе. И автор показал, как он может быть ускорен самой java. А ваши доводы пока что не подтверждены никакими реальными примерами.


                                                                  Так что лучше я буду выглядеть глупо и верить, что JIT ускорит мой код. Тем более, что я сам видел это неоднократно.

                                                                +1
                                                                В редакторах наверняка нет каких-то полезных (ну или ненужных %) ) фич, в браузере нет всяикх канвасов-вебсокетов, и тд и тп.
                                                                «морду» я и на zx-spectrum кое-как умудрялся делать — и в 48кб помещалось. Естественно, там никто даже не задумывался о том, чтобы работать с таким кол-вом данных, как это есть сейчас. И всякие эти разговоры, что раз в 4к-демо могли впихнуть столько — то у нас вот тут много занимает, они не учитывают, что в 4k-демо подгоняется ТЗ под программу, а в реальной жизни приходится делать наоборот.

                                                                Ладно, это нас на философию потянуло. Я лишь говорил о том, что jvm из 90ых — это не jvm-2016. Туда вкинуто много труда, вылизано очень много всего. По сути, даже в 90ых сравнивали технологию, которой всего пару лет, с гораздо более старым и сформировавшимся gcc.
                                                                  0
                                                                  Естественно, там никто даже не задумывался о том, чтобы работать с таким кол-вом данных, как это есть сейчас.
                                                                  Работали с теми данными, которые были тогда. Я лично редактировал файлы в ~300KiB на кружке по программированию на MSX-2 славным редактором mim. Недавно попробовал открыть лог аналогичного размера каким-то редактором под Android — он умер… вернее его система убила.

                                                                  Мощности современного телефона и MSX-2 сами сравните или вам данные из Wikipedia подтянуть?
                                                                    0
                                                                    Вы тролль похоже… Вам «Мягкое», вы «кислое»…

                                                                    Впрочем посмотрим на ваш пример:
                                                                    — что за телефон (объём и параметры оперативной памяти, объём съедаемый ОС, разрешение экрана)?
                                                                    — что за приложение?
                                                                    Ну а в целом ответ-то на него такой: вы знаете на MSX-2 тоже можно было наговнокодить. Это было чуть-чуть сложнее из-за того, что уровней абстракций в коде было меньше и кода было меньше (из-за значительно меньшего функционала).
                                                                    А простенькое приложение FBReader грузит двухмегабайтный fb2 файл из zip-архива. Спокойно и без проблем.
                                                          +2
                                                          Оптимизация на синтетике, круто конечно, но какова вероятность, что в реальном проекте такое случится, когда вам понадобится в реальном проекте, чтобы всегда приходил список из одного элемента?
                                                            –2
                                                            Ну дык Java же! Вернуть переменные из функции нельзя — вот и приходится извращаться… Обычно правда, используют массив из одного элемента, а не список…
                                                              –2
                                                              да ладно?
                                                              public int getMyInt(){}
                                                              
                                                                –1
                                                                Давайте не делать вид, что вы не знаете о чём речь — а то получается спор ни о чём. Да, у функции есть результат — но иногда нужны и выходные переменные. Которых в Java нет. И все про это знают. И знают как обходить. А вот JIT знает и как эту неэффективность изводить теперь. Круто, конечно, но, может быть, проще было язык поприличнее сделать изначально?
                                                                  0
                                                                  Кому нужны и зачем?
                                                                  Вы уверены, что не пытаетесь «писать на Фортране» лишь потому, что так привыкли делать, а вовсе не потому, что это действительно «нужно»?

                                                                  > Круто, конечно, но, может быть, проще было язык поприличнее сделать изначально?

                                                                  Это всего лишь эмоции, а не аргумент.
                                                                  Руководствоваться эмоциями при выборе инструмента — не лучшая идея.
                                                                    +1
                                                                    Пример из статьи относится к итерации (и ее уничтожению JITом) итератором по списку из одного элемента.
                                                                    При возврате переменной костылем в виде массива из одного элемента нет ни циклов, ни итераторов для уничтожения JITом.
                                                                    • UFO just landed and posted this here
                                                                        0
                                                                        Насколько я понял, они хотят, чтобы функция возвращала сразу несколько объектов.
                                                                          +6
                                                                          Мне кажется спор о передаче переменной по ссылке.
                                                                            +4
                                                                            Не джавист, но думаю что он хочет передачу переменной в качестве аргумента метода по ссылке.
                                                                            +5

                                                                            Сделано нормально именно сейчас. У языка Java есть очень крутое свойство: локальную переменную метода может изменить только непосредственно сам этот метод и никто другой. Это существенно упрощает жизнь и спасает от кучи багов, особенно при многопоточном программировании. Не говоря уже о том, как помогает оптимизировать код JIT-компилятору и работать статическим анализаторам. Вы хотите передачу по ссылке? А если вызываемый метод запустит новый тред и обновит переменную уже в нём? Вызвав метод и передав туда локальную переменную, вы не будете знать, когда она изменится. Вся надёжность накроется медным тазом.


                                                                            Иногда если что-то не сделано, это гораздо лучше, чем если что-то сделано. Тут выбор сознательный и очень хороший. Лучше, когда язык умеет меньше, но ты точно знаешь, что происходит.

                                                                        +5

                                                                        Хороший вопрос. В реальном приложении этот метод полностью заинлайнится в точку вызова, причём в разные точки по-разному. Там, где singletonList, он свернётся в чтение поля. Там, где другой тип, будет более сложный код. В один пост подробный анализ этой ситуации уже не лез :-)

                                                                          0
                                                                          Возможно, ноги у этой оптимизации растут из чего-то вроде
                                                                          logger.log("message {0}", oneArg);
                                                                          

                                                                          где logger.log принимает на вход строку и массив объектов.
                                                                          +3
                                                                          Это тоже самое, что написать int main() { return 0; } и сказать, что С++ всё еще самый быстрый по скорости. Такого кейса, как у автора, в жизни вообще быть не может. Уж извините.
                                                                            0
                                                                            Кто может объяснить, вот этот момент
                                                                            // Проверка на safe-point. С её помощь JVM может забрать контроль у скомпилированного кода, например, для сборки мусора.
                                                                            test %eax,-0x27b759f(%rip)

                                                                            не понимаю, как тест позволяет забрать контроль
                                                                              +2
                                                                              не понимаю, как тест позволяет забрать контроль


                                                                              Этот адрес находится на read-protected странице. Происходит прерывание, обработчик которого и взведет java треды на сейфпоинт. Это такой быстрый if. То есть быстрый он тогда, когда идти на safepoint не надо, а если надо — то там и так будет пауза, потомы накладные расходы, связанный с отработкой прерывания минимальны.

                                                                                +3
                                                                                То есть не так. Если рантайм хочет, чтобы все треды пошли на сейфпоинт — он делает эту страницу read-protected. В остальное время чтение возможно. JVM устанавливает свой обработчик прерываний. При чтении происходит прерывание, обработчик которого и взведет java треды на safepoint. Это такой быстрый if. То есть быстрый он тогда, когда идти на safepoint не надо, а если надо — то там и так будет пауза, потому накладные расходы, связанные с отработкой прерывания, несущественны.
                                                                                  0
                                                                                  Спасибо, забавная реализация, видимо чтобы не делать условных операторов.
                                                                                  0
                                                                                  Можно узнать, а каким образом жвм живёт после «сегфолта»? Продолжает работать, только уже из обработчика сигнала?
                                                                                    0

                                                                                    Продолжает, конечно. Что с ней сделается-то? А что происходит с компьютером, если программа падает с сегфолтом? Продолжает ведь работать. С точки зрения процесса нет особой разницы, обработчик прерывания в коде операционной системы или в коде текущего приложения (виртуальной машины).

                                                                                      0
                                                                                      После обработчика она будет продолжена с того места, где оно упало. И будет бесконечно пытаться прочитать не читаемое. Наверное я криво сформулировал вопрос.

                                                                                      Как продолжить программу дальше? Разрешить рид перед завершением? А как тогда потом поймать другие?
                                                                                        +4
                                                                                        Паркуются все потоки, выполняется нужная работа (например сборка мусора), разрешается чтение, все потоки запускаются снова.
                                                                                        Когда снова надо будет запарковать потоки — снова сменить разрешение на страницу памяти.
                                                                                          +2
                                                                                          кармы нету голосовать, но всё именно так. В разных JVM реализовано по-разному, где-то это глобальная страница, где-то это per thread. Вцелом такой механизм называется page polling.
                                                                                            0
                                                                                            Т.е. ждёт «сегфолта» у каждого потока на такой точки? Но в целом понятно — типичный стопворлд о котором я даже не предполагал. Бывает.
                                                                                              0
                                                                                              Если вы запустите хотспот под gdb, то он почти сразу начнет «подать» с такими сегфолтами, сразу надо настраивать gdb, чтобы он игнорировал эти прерывания. Но не в дебаггере этого не видно.

                                                                                              И это не обязательно stop the world. Так реализуют, хоть и не в openjdk, механизм per thread safepoint, когда надо гарантировать, что каждый thread зайдет в сервисную рутину, но после того может продолжить работу, не дожидаясь остальных.
                                                                                                +1
                                                                                                В jvm многие редкие события обрабатываются через сигналы. Именно для того, чтобы в обычном сценарии работы накладные расходы были минимальны.
                                                                                                И, кстати, даже это оптимизируется в рантайме, например: считается, что NPE — редкое событие. Так что разименование нулевого указателя обрабатывается через сигнал. Но если у вас в методе часто падают NPE, то компилятор перекомпилирует этот метод с явными проверками.
                                                                                              +2
                                                                                              Обработчик сигнала не обязан вернуться ровно на ту же инструкцию. В хендлер передаётся ucontext с указателем на сохранённые значения всех регистров. Достаточно заменить значение, соответствующее регистру IP, чтобы по выходу из обработчика сигнала управление передалось на следующую инструкцию или в любое другое место. Например, при разыменовании нулевого указателя хендлер передаёт управление коду, бросающему NullPointerException.
                                                                                                0
                                                                                                Спасибо. Когда-то давно я пытался что-то подобно делать со сменой ip, но у меня не получалось. Возможно не осилил. Оно точно работает? Хотя как время будет — попробую перепроверить.
                                                                                                  +1
                                                                                                  Точно. Делается примерно так:
                                                                                                      ucontext->uc_mcontext.gregs[REG_RIP] = new_return_address;
                                                                                                  

                                                                                                  На x86 — REG_EIP, на amd64 — REG_RIP.
                                                                                      0
                                                                                      У меня 3 вопроса.
                                                                                      1. Почему в из Hotspot до сих пор не выкинули вообще интерпретатор? Почему Google в V8 сделала это, а Oracle — нет?
                                                                                      2. Какая производительность чистого интерпретатора в Hotspot — кто-нибудь измерял, забавы ради?
                                                                                      3. Почему в явасрачах сразу же не фиксируется базовая установка: Java — для бэкенда, для «серверных» сценариев нагрузки, когда Hotspot выполняет большую часть времени небольшую, «горячую» часть программы, может власть всё заоптимизировать и закешировать? Иногда, когда такой тип нагрузки встречается в «настольных» приложениях, Java работает вполне сносно, если не считать относительно долгий запуск и повышенные требования к памяти. Но почему-то мало кому приходит в голову писать на Java браузеры, например, или медиа-кодировщики. Хотя, казалось бы, тут Java прямо напрашивается, т.к. сложность проектов зашкаливает. А причина проста — характер нагрузок просто не позволит Hotspot развернуться, ну и память тоже. Хотя, учитывая сколько памяти ест Хром — может даже Java эффективнее с ней работала.
                                                                                        0
                                                                                        1. Почему в из Hotspot до сих пор не выкинули вообще интерпретатор?
                                                                                        Например потому что куски кода, которые отрабатывают всего один раз часто быстрей проинтерпретировать, чем скомпилировать + сохранить + выполнить.
                                                                                          0
                                                                                          Это могло быть правдой, если бы Google не доказал, что «черновая» компиляция — простая замена базовых логических блоков на соответствующий машинный код — почти ничего не стоит. И чтобы блок кода попал под C2, он должен выполниться далеко не 2 раза, а сильно больше.
                                                                                            +2
                                                                                            Вы пробовали смотреть top или smem -t когда играете в какой-нибудь sither io?

                                                                                            У меня кушается проца 250% и памяти 4 процесса: 370+170+140+150 = 830м.
                                                                                            jvm столько будет жрать на довольно больших программах (например нетбинс жрет около 700m), хром — ест это просто потому, что хочет. И c ff ситуация обстоит примерно так же. Интерпретатор жрет мало, позволяет выбрасывать редкоиспользуемый код, или вовсе не производить его. Поэтому, java жрет по сравнению с подходом «компильнуть вообще все» меньше памяти и меньше проца.

                                                                                            Попробовала бы какая-нибудь idea постоянно 250% кушать. Все бы говорили, что idea тормозит и жрет проц, но для хрома это ок, никому даже в голову не приходит сказать, что это плохо. Всем, кто не жава «разрешено» жрать много.
                                                                                              0
                                                                                              Простите, я не понимаю — какое отношение непонятно как написанная и неизвестная мне игра имеет к моему вопросу? Даже если не учитывать, что я не играю в игры.
                                                                                              Java ест столько, сколько дадут. Как и Chrome. С FF ситуация обстоит совершенно не так же.
                                                                                              Черновой компилятор V8 ест мало, работает быстро. Интерпретатор в Java ничего не выкидывает — это делает HotSpot.
                                                                                              Помимо V8 в Chrome есть кому память съесть. Нет никаких доказательств, что подход Chrome хоть чем-то хуже подхода JVM.
                                                                                              Зато есть немало доказательств, что непрогретый Java-код мягко говоря не оптимален — вот, например: https://github.com/floatdrop/v8-vs-java-bench.
                                                                                              Как и вечные жалобы на многочисленные бенчмарки: вы всё врёти! у вас ява не прогрета!
                                                                                                +2
                                                                                                Прямое отношение оно имеет — работает на js в хроме.
                                                                                                А зачем доказывать, что непрогретый код — неоптимален? И зачем вы мне дали сравнение оптимальности по CPU, если я говорил про лучшую оптимальность по памяти?
                                                                                                То, что непрогретое неоптимально по CPU — это и так известно, но всем плевать на это. Все силы брошены на компилятор — и это правильно. Интерпретатором оракл если и начнет заниматься — то когда совсем нечего будет делать.

                                                                                                Ваш пример, кстати, падает где-то в js после теста с++ и java. То есть, Автор не в состоянии написать непадающий код, и непонимает что он меряет — но уже делает выводы о непригодности и тормознутости технологии, которой пользуются весь мир. Сразу видно — большой специалист.

                                                                                                То, что вы дали — канонический пример непонимания, что вообще происходит, и как работают программы. Там не интерпретатор меряется, а время старта самой vm. Наличие или отсутствие тела у метода main не влияет на конечный результат. (и если починить чтоб не падало, оно скорей всего не будет влиять ни в js ни в ruby ни в python)

                                                                                                Я вас научу правильно отсеивать заведомо плохие тесты. Если видите, что в тесте написано имя java-класса с маленькой буквы — весь тест можно сразу выбрасывать не глядя и не разбираясь. Все равно там что-нибудь сделано неверно, и меряется не то, на что рассчитывает автор.
                                                                                                  0
                                                                                                  Ок, игра на JS в хроме. Тормозит. Было бы странно, если бы не тормозила :)
                                                                                                  Читаем изначальный вопрос. Думаем. Догадываемся, что он не про скорость работы, а про скорость чернового компилятора.
                                                                                                  Который ни разу много не ест и не тормозит. Тормозит всё потом уже, и память ест потом. Уже когда и основной компилятор отработает, когда кеши заполнятся, когда данные прогрузятся все.
                                                                                                  Но при этом даже черновой компилятор V8 в несколько (предположительно) раз быстрее интерпретатора.
                                                                                                  И это видно в тех тестах, когда из-за малого количества итераций ни у V8, ни у HotSpot основные компиляторы отработать не успевают: JVM с треском проигрывает.
                                                                                                  А что тот тест падает — не удивительно, учитывая дату последнего коммита. И не именно в нём дело.
                                                                                                  Про время старта JVM убедительно написано тут, просвещайтесь: http://benchmarksgame.alioth.debian.org/sometimes-people-just-make-up-stuff.html#jvm-startup-time
                                                                                                    +3
                                                                                                    Сам компилятор может не ест и не тормозит — но производимый код, очевидно, плох: и ест и тормозит. Иначе и быть не может. Долгий компилятор — хороший(может быть) код, быстрый компилятор — плохой(всегда будет) код. В V8 компилятор быстрый. В jvm — несколько разных компиляторов, что позволило сделать быстрый старт (все равно на старте часто бывает, что user-код сканирует classpath — т.е. идет активная работа с диском) — и быструю работу потом. Отличии от того же шарпа, где медленный старт — и относительно-медленная (как у С1) работа.

                                                                                                    Вам написали — если выполнять код надо однократно, то быстрей всего его интерпретировать. И по памяти это, очевидно, меньше. «компилятор V8 всех порвет» — это домыслы автора. Что такое интерпретатор в jvm? Это просто switch-case, причем даже слегка заоптимайзеный при помощи таблицы опкодов и goto. Там нету никакой магии. Он не может быть медленней v8-компилятора.

                                                                                                    Тогда почему в том тесте померяны тормоза? А вот почему.

                                                                                                    Мы уже выяснили выше, что люди, на которых ссылались, не умеют корректно измерять величины, писать тесты производительности, и не понимает, что именно меряют, и почему результаты такие. Это не V8 у него работает быстрей jvm-интерпретатора, а V8 у него стартует и завершается быстрей, чем у него стартует и завершается jvm. Убедится в этом, как я написал выше, можно, убрав тело метода main. На время исполнения всей программы это особо не отразится — что свидетельствует о том, что сама интерпретация тела пренебрежимо мала по сравнению с загрузкой-шатдауном jvm.

                                                                                                    Допустим даже v8 хоть в миллион раз быстрей стартует. Лично меня это особо не волнует. Старт jvm все равно визуально-моментален, но мне важно, чтобы потом оно качественно работало, а не поглощало память и проц, как это делает V8.

                                                                                                    Кстати, а что не так с датой последнего коммита? Если она старая — оно по-вашему может неработать? Эпично! В java такой фигни нет! :)))

                                                                                                    jvm стартует немножко дольше потому, что делает больше действий, которые позволяют ей в будущем работать лучше. Т.е. считайте это уклоном в сторону «медленней компилятор — лучше код». Кроме того, у автора тестов мог быть медленный винт. У java большой рантайм, ~64мб еще и позипован. Медленный винт вполне мог оказать решающую роль. Это действительно не очень хорошо, но масштаб трагедии — понт. Скажем так, хотспот проигрывает — но не с треском, а с потрескиванием головок винчестера. Кстати, ждем девятку, там это должны улучшить, т.к. растащат функционал по модулям. Но все равно, из зипа jvm загружает только то, что реально использует. И все равно, в сколь-нибудь серьезных приложениях значительная часть рантайма используется.
                                                                                          +1

                                                                                          Вообще вы можете запустить HotSpot с флагом -XX:-UseInterpreter. Вы можете сами потестировать, будет ли ваше приложение работать от этого быстрее. По моим прикидкам обычно интерпретатор медленнее, чем C2-код в 20-100 раз. Разумеется, всегда можно придумать тест, где цифра сильно изменится в любую сторону. Java-таки не для бэкэнда, это универсальный язык программирования.

                                                                                            +3
                                                                                            Немного не так. -XX:-UseInterpreter не отключает интерпретатор. Для форсированного выполнения скомпилированного кода служит флаг -Xcomp, который эквивалентен -XX:-UseInterpreter -XX:-BackgroundCompilation -XX:-ClipInlining -XX:Tier3InvokeNotifyFreqLog=0 -XX:Tier4InvocationThreshold=0

                                                                                            Это будет хорошим приближением работы в полностью компилируемом режиме. Но на самом деле, HotSpot не умеет работать вообще без интерпретатора.
                                                                                              0

                                                                                              Спасибо за поправку! А отдельно -XX:-UseInterpreter без всего остального что будет значить?

                                                                                                +1
                                                                                                При ресолвинге одного из invoke* байткодов либо при вызове из натива метод будет помещаться в очередь на компиляцию. При этом, если background компиляция не отключена, метод спокойненько продолжит исполняться в интерпретаторе.
                                                                                            –3
                                                                                            Почему Google в V8 сделала это, а Oracle — нет?
                                                                                            Потому что они работают с разными входными данными. V8 нужно в любом случае скомпилировать программу (поступает-то она в виде декста, так что всё равно нужно распарсить этот текст, преобразовать в внутреннее представление и т.д. и т.п.). Можно компилировать в промежуточный байткод, можно — прямо в машинный (по-быстрому, без оптимизаций).

                                                                                            Хотя, учитывая сколько памяти ест Хром — может даже Java эффективнее с ней работала
                                                                                            Не работала бы. Вот прямо сейчас у меня запущено 70 процессов Хрома. Запуск сравнимого числа JVM приведёт к тому, что жалких 8GiB памяти не хватит — даже если там будут крутиться «Hello, World»'ы. Безопасно запускать много процессов в одной JVM — тоже нельзя (Oracle это признал, когда отказался даже от попыток сделать вид, что HostSpot способен обеспечить безопасность, и превратил Java в ActiveX--).

                                                                                            В общем я не знаю ни одной задачи, которую Java обещала бы решить — и при этом успешно решила (только не надо про «умные IDE»: если бы столько денег, сколько вбухали в разработку IDE для Java на Java вбухали бы в IDE на C++ для C++ — результат был бы не хуже).
                                                                                              0
                                                                                              Есть множество реализаций ЯП, которые интерпретируют код построчно или поблочно, без какого-либо промежуточного представления. Собственно, все изначальные реализации JS именно так и работали.

                                                                                              Я понимаю, и частично разделяю ваш скепсис к скорости работы и потребляемым ресурсам приложений на Java. Но надо признать, что при условии предоставления достаточных объёмов памяти, чего никто не скрывает, оно зачастую работает вполне прилично и быстро.

                                                                                          Only users with full accounts can post comments. Log in, please.