Ответ 1
"Принцип проектирования" JIT состоит в том, чтобы компилировать метод (экземпляр метода для общих методов) один раз и повторно использовать один и тот же собственный код. Конечно, реализация чрезвычайно сложна, и я попытаюсь упростить ответ без ущерба для точности. Ответ одинаковый для всех версий среды выполнения с .NET 2.0 и до последнего .NET 4.6 (я не знаю о .NET 1.x, возможно, тот же).
Обратные вызовы профилировщика времени выполнения и события ETW плохо документированы. Оба они возникают при попытке компиляции JIT, но не обязательно. Есть три случая, когда это может произойти: 1- метод не отвечает определенным требованиям безопасности, 2 - проверка метода не удалась, и 3-я память не могла быть выделена для хранения исходящего кода. Таким образом, обратный вызов и событие запуска JIT могут переоценить количество случаев, когда метод фактически был скомпилирован. Аналогичным образом, обратный вызов завершения и события JIT являются неточными. Есть редко встречающиеся случаи, когда они могут недооценивать количество раз, когда тот же метод был успешно скомпилирован. На данный момент стоит упомянуть, что # из методов JITted счетчик производительности точно отражает количество раз, когда все IL-методы были скомпилированы в совокупности во всех областях приложения процесса.
Для ассемблерных ассемблеров методы компилируются в каждом приложении отдельно. Нет совместного доступа (хотя иногда это может быть технически возможно). Для групп, не поддерживающих appdomain, время выполнения пытается компилировать каждый метод один раз и совместно использовать собственный код со всеми доменами приложения.
Как доказать, что .NET CLR JIT компилирует каждый метод только один раз за работать?
Ну, в некоторых случаях (например, при использовании фона JIT и других чрезвычайно тонких случаях) метод может быть скомпилирован, даже не будучи выполненным. Таким образом, каждый метод скомпилирован один раз за прогон. Неверный.
Вы можете обратиться к исходному коду CoreCLR JIT для получения дополнительной информации (JIT - это тот же самый, который используется в .NET Framework 4.5+, но этот ответ относится к более старым версиям, поскольку механизм запуска JIT в основном одинаков). Исходный код является доказательством.
методы JITted для каждого объекта в потоке
Да, это не имеет никакого смысла. Объем компиляции - это приложения.