Эффективность Java, JIT и сборщика мусора - PullRequest
4 голосов
/ 09 апреля 2011

Я хочу знать об эффективности Java, а также о преимуществах и недостатках Java Virtual Machine и Android. Эффективность - низкое использование памяти, низкое использование процессора и быстрое выполнение.

Мобильные устройства проще, чем ПК, поэтому приложения должны быть более эффективными. Серверы получают много соединений, и они должны быть очень эффективными. Многие мобильные устройства используют приложения Android и Java, а многие серверы используют PHP.

Может ли Java и интерпретируемые языки, такие как Java Script, Python и PHP, быть более эффективными, чем C и C ++?

JIT (как раз вовремя) преимущества:

  • Он может оптимизировать лучше, потому что он знает значение некоторых переменных и где он используется или изменен.
  • Он знает процессор и может оптимизироваться с помощью инструкций, специфичных для процессора.
  • Проще преобразовать функции во встроенную функцию.
  • Может удалять известные условные тесты и удалять блоки, которые не будут запускаться.

Недостатки Java:

  • Когда приложение запускается в первый раз, оно будет работать очень медленно, поскольку байт-коды будут интерпретироваться, а JIT-компилятор будет выполнять много анализов, чтобы найти хорошие оптимизации. Приложения не могут использовать максимум мощности оборудования. Если приложение представляет собой игру или приложение реального времени, если оно будет запущено в первый раз успешно и без задержки, но оно использует максимум мощности оборудования, то при следующем запуске приложения оно не будет использовать максимальная аппаратная мощность за счет оптимизации. Проблема в том, что приложение не может быть спроектировано так, чтобы использовать максимум аппаратной мощности после оптимизации, поскольку оно будет слишком медленным при первом запуске и не будет продолжать работать.
  • Java проверяет, не выходит ли индекс массива за пределы, и проверяет, не являются ли указатели нулевыми. Это добавит несколько внутренних «если» к сгенерированному коду.
  • Все объекты используют сборщик мусора, включая объекты, которые очень легко удалить вручную.
  • Все экземпляры объектов создаются с динамическим распределением памяти, включая объекты, которые могут легко использовать стек. Если итерация цикла начинает создавать экземпляр класса и завершает удаление созданного объекта, динамическое распределение памяти будет неэффективным.
  • Сборщик мусора должен остановить приложение, пока он очищает память, и это очень нежелательно для игр, приложений с графическим интерфейсом и приложений в реальном времени. Подсчет ссылок идет медленно и не может обрабатывать циклические ссылки. Многопоточный сборщик мусора работает медленнее и требует большего использования процессора.

Ответы [ 5 ]

5 голосов
/ 09 апреля 2011

Может ли Java и интерпретируемые языки, такие как Java Script, Python и PHP, быть более эффективными, чем C и C ++?

Очень сложно стать более эффективным, чем лучшие программы на C и C ++. Есть много программ на C и C ++, которые еще не настолько эффективны, как это, и победить их с помощью (современного) Java-кода вполне практично, если вы хороши. Я также слышал хорошие новости о современных лучших Javascript движках, но я никогда не изучал их подробно.

С Python и PHP (и многими другими языками, кроме) все немного по-другому. Эти языки написаны на C , поэтому очевидно, что они не могут быть более эффективными, чем C (следует по построению). Тем не менее, гораздо проще написать эффективный код в них (то есть, который использует, по сути, очень хорошо написанную библиотеку C), чем начинать с нуля. В частности, это уменьшает количество дефектов на программу. Это очень важный показатель на практике; любой может создать быстрый код, если он допустит ошибку.

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

3 голосов
/ 10 апреля 2011

Давайте разберем ваши заявленные недостатки:

  • Когда приложение запускается в первый раз, оно будет очень медленным, потому что байт-коды будут интерпретироваться, а JIT-компилятор выполнит много анализа, чтобы найти хорошие оптимизации. Приложения не могут использовать максимум мощности оборудования.

JIT-компиляция является проблемой реализации. Не все платформы делают это. Действительно, платформу Android можно было бы изменить на 1) выполнять предварительную компиляцию или 2) кэшировать собственный код, созданный JIT, чтобы ускорить запуск при следующем запуске приложения.

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

  • Java проверяет, не выходит ли индекс массива за пределы, и проверяет, не являются ли указатели нулевыми. Это добавит несколько внутренних «если» к сгенерированному коду.

JIT-компилятор может оптимизировать многие из этих тестов. В остальном накладные расходы имеют тенденцию быть относительно небольшими; например разница в несколько процентов ... не в 2 раза.

Обратите внимание, что альтернативой проверке является риск того, что типичные ошибки приложения могут привести к сбою платформы Android. Конечно, сборка мусора становится проблематичной, если приложения могут загружать память.

  • Все объекты используют сборщик мусора, включая объекты, которые очень легко удалить вручную.

Обратной стороной является то, что легко забыть удалить объекты, удалить объекты дважды, использовать их после того, как они были удалены, и так далее. Все эти ошибки приводят к ошибкам, которые трудно отследить.

  • Все экземпляры объектов создаются с динамическим распределением памяти, включая объекты, которые могут легко использовать стек. Если итерация цикла начинает создавать экземпляр класса и завершает удаление созданного объекта, динамическое распределение памяти будет неэффективным.

Динамическое выделение памяти Java и создание объектов - БЫСТРО. Например, быстрее, чем в C ++.

  • Сборщик мусора должен остановить приложение, пока он очищает память, и это очень нежелательно для игр, приложений с графическим интерфейсом и приложений в реальном времени.

Тогда используйте параллельный сборщик мусора с низкой паузой. Другой подход заключается в том, чтобы ваше приложение не создавало много мусора ... и редко запускало сборку мусора.

  • Подсчет ссылок идет медленно и не может обрабатывать циклические ссылки.

Нет достойного Java GC использует подсчет ссылок. (С другой стороны, многие схемы управления памятью на C / C ++ подходят. Например, так называемые схемы интеллектуальных указателей в C ++.)

  • Многопоточный сборщик мусора работает медленнее и требует большего использования процессора.

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

2 голосов
/ 09 апреля 2011

То, что вы описываете как «эффективный», я бы назвал «идеальным».Приложение, которое требует мало памяти, мало процессорного времени и работает быстро, другими словами, является хорошим, быстрым и дешевым одновременно.Не берите в голову, делает ли это что-нибудь полезное или интересное.

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

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

Но на самом деле вопрос: может ли язык, подобный Java, создавать более эффективный код, чем тот, которыйстатически компилируется в набор команд целевой машины?Возможно нет.Это может быть столь же эффективно, или достаточно эффективно?Абсолютно.Если бы мы рассматривали платформу выполнения с фиксированными, строго ограниченными ресурсами, которые меняются редко, это было бы другое дело.

1 голос
/ 10 апреля 2011

Я вставлю интересный ответ, данный самим Джеймсом Гослингом, в Книгу Создатели программирования .

Ну, я слышал, что это говорит о том, что фактически у вас есть два компилятора в мир Java. У вас есть компилятор в байт-код Java, и тогда у вас есть ваш JIT, который в основном перекомпилируется опять все конкретно. Все ваши страшные оптимизации находятся в JIT .

Джеймс: Точно. В эти дни мы бить действительно хорошие C и C ++ компиляторы почти всегда Когда ты перейти к динамическому компилятору, вы получите два преимущества, когда компилятор работает прямо в последний момент. Один Вы точно знаете, какой чипсет ты бежишь дальше. Так много раз, когда люди собирают кусок C код, они должны скомпилировать его для запуска на вид общего x86 архитектура. Почти никто из двоичные файлы, которые вы получаете, особенно хорошо настроенный на любой из них. Вы скачиваете последняя копия Mozilla, и это будет работать практически на любом Intel Архитектура процессора. Там довольно много один бинарный Linux Это довольно общее, и это скомпилировано с GCC, который не очень хороший компилятор Си.

Когда работает HotSpot, он точно знает на каком чипсете вы работаете. Это точно знает, как работает кеш. Это точно знает, как иерархия памяти работает. Он точно знает, как все работа конвейерной блокировки в процессоре. Он знает, что набор инструкций У этого чипа есть расширения. Это оптимизирует именно для какой машины Вы на. Тогда другая половина является то, что он на самом деле видит приложение работает. Это в состоянии иметь статистику, которая знает, какие вещи важны. Это в состоянии встроенные вещи, которые мог компилятор C никогда не делай. Вид вещей, которые получают встраивается в мир Java довольно удивительно. Затем вы придерживаетесь этого способ управления хранением с современные сборщики мусора. С современный сборщик мусора, склад распределение очень быстро.

Masterminds of Programming

1 голос
/ 10 апреля 2011

На любом языке способ получить быстрое выполнение состоит в том, чтобы выполнять работу с минимально возможным выполнением и минимальным сбором мусора, насколько это возможно.

Это звучит как пустая общность, но что это означаетна практике, независимо от языка, это

  1. Для проектирования структуры данных, сделайте его максимально простым.Держитесь подальше от классных коллекций, полных наворотов.Особенно держитесь подальше от уведомлений как способа обеспечения согласованности данных.Если ваши данные нормализованы, они никогда не будут противоречивыми.Если вы не можете его нормализовать, лучше мириться с временным несоответствием, чем пытаться сохранить его с помощью уведомлений.

  2. Проблемы производительности возникают даже в самом лучшем коде.Вы должны стараться не делать их, но вы все равно будете их делать.Самое важное - это знать, как их найти, сделать и удалить. Вот пример за ударом. Если при этом вы обнаружите, что вам нужен лучший алгоритм big-O, вставьте его. Вставка одного без уверенности в том, что он необходим, - это рецепт медлительности.

Ни один язык не может спасти программу от неустранимых проблем с производительностью.Язык и его компилятор, JITter и т. Д. Похожи на скаковых лошадей.Хорошо хотеть хорошую лошадь, но это пустая трата, если жокей не настолько худ, насколько это возможно .Ваша программа - это жокей, и ваша задача - использовать ее в программе похудения.

...