.NET CLR JIT каждый раз компилирует каждый метод? - PullRequest
26 голосов
/ 10 августа 2009

Я знаю, что Java HotSpot JIT иногда пропускает JIT-компиляцию метода, если ожидает, что издержки компиляции будут ниже, чем издержки запуска метода в интерпретируемом режиме. Работает ли .NET CLR на основе похожей эвристики?

Ответы [ 4 ]

44 голосов
/ 10 августа 2009

Примечание. Этот ответ относится к контексту "за выполнение". Код обычно JITted каждый раз, когда вы запускаете программу. Использование ngen или .NET Native также меняет эту историю ...

В отличие от HotSpot, CLR JIT всегда компилирует точно один раз за цикл. Он никогда не интерпретирует и никогда не перекомпилируется с более тяжелой оптимизацией, чем раньше, исходя из фактического использования.

Конечно, это может измениться, но так было с v1, и я не ожидаю, что оно скоро изменится.

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

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

РЕДАКТИРОВАТЬ: выше описывает каркас рабочего стола. Компактный каркас выдает нативный код, когда захочет, JITting снова при необходимости. Однако это не похоже на адаптивную оптимизацию HotSpots.

Микро-фреймворк вообще не JIT, интерпретируя вместо этого код. Это имеет смысл для очень ограниченных устройств. (Не могу сказать, что много знаю о микроуровне.)

14 голосов
/ 10 августа 2009

Среда выполнения .NET всегда компилирует код JIT перед выполнением. Таким образом, это никогда не интерпретируется.

Более интересное прочтение можно найти в Выбор дизайна CLR с Андерс Хейлсберг . Особенно часть:

Я читал, что Microsoft решила, что IL всегда будет компилироваться, а не интерпретироваться. Как информация о типах кодирования в инструкциях помогает переводчикам работать более эффективно?

Андерс Хейлсберг: Если переводчик может просто слепо делать то, что говорится в инструкциях, без необходимости отслеживать, что находится наверху стека, он может идти быстрее. Например, когда он видит iadd, интерпретатору не нужно сначала выяснять, какой тип добавления он добавляет, он знает, что это целочисленное добавление. Предполагая, что кто-то уже проверил, что стек выглядит правильно, можно безопасно сократить время, и вы заботитесь об этом для переводчика. В нашем случае, однако, мы никогда не намеревались нацеливать интерпретируемый сценарий на CLR. Мы намеревались всегда JIT [Компиляция точно в срок], и для целей JIT нам все равно нужно было отслеживать информацию о типе. Поскольку у нас уже есть информация о типе, на самом деле нам ничего не нужно вкладывать в инструкции.

Билл Веннерс: Многие современные JVM [виртуальные машины Java] проводят адаптивную оптимизацию, где они начинают с интерпретации байт-кодов. Они профилируют приложение во время его выполнения, чтобы найти от 10% до 20% кода, который выполняется от 80% до 90% времени, а затем компилируют его в native. Тем не менее, они не обязательно вовремя компилируют эти байт-коды. Байт-коды метода могут все еще выполняться интерпретатором, поскольку они компилируются в нативный и оптимизируются в фоновом режиме. Когда нативный код готов, он может заменить байт-коды. Не нацеливаясь на интерпретируемый сценарий, полностью ли вы исключили такой подход к выполнению в CLR?

Андерс Хейлсберг: Нет, мы не полностью исключили это. Мы все еще можем интерпретировать. Мы просто не оптимизированы для интерпретации. Мы не оптимизированы для написания того самого высокопроизводительного интерпретатора, который будет интерпретировать только когда-либо. Я не думаю, что кто-то делает это больше. Для приставки 10 лет назад это могло бы быть интересно. Но это уже не интересно. Технологии JIT дошли до того, что вы можете иметь несколько возможных стратегий JIT. Вы даже можете представить себе использование быстрого JIT, который просто быстро разрывается, а затем, когда мы обнаруживаем, что мы выполняем определенный метод все время, используя другой JIT, который тратит немного больше времени и лучше оптимизирует работу. Вы можете сделать гораздо больше в JIT.

3 голосов
/ 26 июня 2010

Будет приятно увидеть в будущем некоторые основанные на трассировке JIT для устройств с нехваткой памяти. Он будет в основном интерпретировать, находить горячие точки, конвертировать их в ассемблер и кэшировать их. Я думаю, это то, что Google делает со своим Android JIT, и Microsoft Research проводит исследовательский проект для основанного на трассировке JIT.

Я нашел статью, SPUR: основанный на трассировке JIT-компилятор для CIL .. Может быть, часть этого однажды превратится в CLR

0 голосов
/ 10 августа 2009

Я не верю в это и не думаю, что так должно быть.

Как JIT мог знать, сколько раз будет вызван конкретный метод? Не будет ли частота фактора интерпретации в решении?

Я бы также спросил, насколько хорошо JIT-компилятор сможет анализировать функцию, чтобы определить, будет ли лучше интерпретация без интерпретации самой функции. И учитывая тот факт (что по крайней мере один проход метода состоялся), не лучше ли было бы просто скомпилировать каждый метод, чтобы уменьшить накладные расходы на попытки определить, какие методы компилируются в первую очередь?

...