Что делает компилятор Java настолько быстрым?

Мне было интересно, что делает основной компилятор Java (javac by sun) настолько быстрым при компиляции?

.., а также компилятор С#.NET от Microsoft.

Я сравниваю их с компиляторами С++ (например, g++), поэтому, возможно, мой вопрос должен был быть, что делает компиляторы С++ настолько медленными:)

Ответ 2

Я думаю, что самой сложной частью является не необходимость компилировать файлы заголовков (если они не очень большие, но вы можете использовать предварительно скомпилированные заголовки в этом случае). Худшая часть - это всегда тот факт, что грамматика С++ слишком дикочувствительна к контексту. Несмотря на то, что мне нравится С++, мне жаль кого-либо, кто должен написать парсер С++.

Ответ 3

Есть несколько вещей, которые делают компилятор С++ медленнее, чем язык Java/С#. Грамматика намного сложнее, общая поддержка программирования намного более сильная на С++, но в то же время ее дороже компилировать. Включение файлов работает по-другому, чем импорт модулей.

Включение заголовочных файлов

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

Java (или С#, я буду говорить о Java, но они похожи в этом) не содержат файлов, они зависят от двоичных файлов из компиляции используемых классов. Это означает, что всякий раз, когда вы компилируете a.java, который использует объект B, определенный в b.java, он просто проверяет двоичный b.class, ему не нужно углубляться, чтобы проверить зависимости B, чтобы он мог сократить процесс раньше (только с одним уровнем проверки).

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

Итак, в конце, на C/С++ больше файлов включены, и в то же время обработка этих включений стоит дороже обработки двоичных модулей.

Шаблоны

Шаблоны являются особенными по-своему. Они могут быть предварительно скомпилированы, но обычно их нет (по хорошему набору причин). Это означает, что во всех единицах компиляции, которые используют std::vector, обрабатывается весь набор векторных методов (неиспользуемые методы шаблонов не компилируются) и двоичный код, сгенерированный компилятором. На более позднем этапе при связывании избыточные определения одного и того же метода будут удалены, но во время компиляции они должны быть обработаны.

Поддержка в Java для дженериков более ограничена во многих отношениях. В конце, например, существует только один двоичный объект класса Vector, и всякий раз, когда компилятор видит Vector в java, то что он делает, это генерировать код проверки типов перед передачей в реальную реализацию Vector (которая хранит простой объект), и это не является общим. Компилятор предоставляет гарантии типа, но не компилирует Vector для каждого типа.

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

Ответ 4

Поскольку они делают что-то совсем другое, компилятор С++ создает оптимизированный собственный код, тогда как компилятор С#, VB.Net и Java создает промежуточный язык, чем при первом запуске приложения, превращается в собственный код, и поэтому вы получаете медленную загрузку приложения в Java и т.д. при первом запуске приложения.

Компилятор С++ должен выполнить полную оптимизацию, когда языки JITed оптимизируются при выполнении приложения.

Кто-то будет утверждать, что вам нужно измерить время компиляции С++ = время компиляции Java + время для JITing при первом загрузке приложения, если вы хотите быть правильным, но я не думаю, что это было бы правильно и справедливо, потому что вы сравнивают родные языки с JITed или апельсины с яблоками.

Ответ 5

Компилятор С++ должен многократно компилировать все файлы заголовков, и их много, поэтому это одна вещь, которая замедляет ее.

Ответ 6

Одной из наиболее трудоемких задач при компиляции является оптимизация кода.

Javac очень мало оптимизирует код при выполнении компиляции. Оптимизация выполняется JVM при запуске приложения.

A C/С++ необходимо оптимизировать при компиляции, поскольку оптимизация скомпилированного машинного кода сложна.

Ответ 7

Вы получили это в своем последнем предложении: это не java или С#, которые быстро компилируются, это С++, который очень медленно компилируется из-за его сложной грамматики и функций, что наиболее важно templates

Ответ 8

Если вы думаете, что javac быстро попробует Jikes.... (см. http://jikes.sourceforge.net/)  Это компилятор Java, написанный на С++. К сожалению, они не справились с последними спецификациями компилятора Java, но если вы хотите быстро это увидеть, это он.

Тони

Ответ 9

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

Ответ 10

Немного сложно сравнить языки байт-кода, такие как java с изначально скомпилированными языками, такими как С++. Лучшее сравнение - Delphi vs С++, где Delphi намного быстрее компилируется. Поскольку это не имеет ничего общего с оптимизацией или байтовым кодом, это должно быть связано с различиями в синтаксисе языка и относительной производительностью включений в сравнении с модулями/единицами.

Ответ 11

Является ли компилятор Java быстрым?

Перевод Java в класс должен быть ослепительно быстрым, поскольку это просто прославленный zip с некоторой проверкой синтаксиса, чтобы быть справедливым по сравнению с реальным компилятором, который делает оптимизацию и генерирование кода объекта, "перевод" с Java на класс тривиальным.

Проведено сравнение с довольно небольшой программой "hello world" и - и сравнивается с GCC (C/С++/Ada) и выяснилось, что javac был в 30 раз медленнее, а во время выполнения он стал еще хуже?