C # 컴파일러 자체는 릴리스 빌드에서 방출 된 IL을 크게 변경하지 않습니다. 주목할 점은 더 이상 중괄호에 중단 점을 설정할 수있는 NOP opcode를 방출하지 않는다는 것입니다. 가장 큰 것은 JIT 컴파일러에 내장 된 최적화 프로그램입니다. 나는 그것이 다음과 같은 최적화를한다는 것을 알고있다.
인라인 방법. 메소드 호출은 메소드의 코드 삽입으로 대체됩니다. 이것은 큰 것으로, 속성 접근자를 본질적으로 무료로 만듭니다.
CPU 레지스터 할당. 지역 변수와 메소드 인수는 스택 프레임에 다시 저장되지 않고 CPU 레지스터에 저장된 상태로 유지 될 수 있습니다. 이것은 최적화 된 코드 디버깅을 어렵게 만드는 데 주목할만한 큰 것입니다. 그리고 휘발성 키워드에 의미를 부여합니다 .
배열 인덱스 검사 제거. 배열 작업시 중요한 최적화 (모든 .NET 컬렉션 클래스는 배열을 내부적으로 사용) JIT 컴파일러가 루프가 범위를 벗어난 배열을 색인화하지 않는지 확인할 수 있으면 색인 검사가 제거됩니다. 큰 것.
언 롤링 루프. 본문에서 코드를 최대 4 번 반복하고 반복 횟수를 줄임으로써 작은 몸체가있는 루프가 개선됩니다. 지점 비용을 줄이고 프로세서의 슈퍼 스칼라 실행 옵션을 향상시킵니다.
데드 코드 제거. if (false) {/ ... /} 와 같은 문장 은 완전히 제거됩니다. 이것은 일정한 접힘과 인라인으로 인해 발생할 수 있습니다. 다른 경우는 JIT 컴파일러가 코드에 부작용이 없음을 확인할 수있는 경우입니다. 이 최적화는 프로파일 링 코드를 매우 까다롭게 만듭니다.
코드 게양. 루프의 영향을받지 않는 루프 내부의 코드는 루프 밖으로 이동할 수 있습니다. C 컴파일러의 최적화 프로그램은 호이스트 기회를 찾는 데 더 많은 시간을 할애합니다. 그러나 필요한 데이터 흐름 분석으로 인해 비용이 많이 드는 최적화이며 지터가 시간을 할애 할 수 없으므로 명백한 경우 만 호이스트합니다. .NET 프로그래머가 더 나은 소스 코드를 작성하고 호이스트하도록 강요합니다.
일반적인 하위 표현 제거. x = y + 4; z = y + 4; z = x가된다; dest [ix + 1] = src [ix + 1]과 같은 문장에서 매우 흔합니다. 도우미 변수를 도입하지 않고 가독성을 위해 작성되었습니다. 가독성을 손상시킬 필요가 없습니다.
일정한 접힘. x = 1 + 2; x = 3이되고; 이 간단한 예제는 컴파일러에 의해 일찍 발견되지만 다른 최적화가이를 가능하게하는 JIT 시간에 발생합니다.
전파를 복사하십시오. x = a; y = x; y = a가된다; 이것은 레지스터 할당자가 더 나은 결정을 내리는 데 도움이됩니다. 작업 할 레지스터가 거의 없기 때문에 x86 지터에서 큰 문제입니다. 올바른 것을 선택하는 것은 성능에 중요합니다.
예를 들어 앱의 디버그 빌드를 프로파일 링하고 릴리스 빌드와 비교할 때 큰 차이를 만들 수있는 매우 중요한 최적화입니다 . 코드가 중요한 경로에있을 때 실제로 중요합니다. 실제로 작성한 코드의 5 ~ 10 % 프로그램 성능에 영향을 미칩니다. JIT 옵티마이 저는 중요한 것이 무엇인지 미리 알기에 충분히 똑똑하지 않으며 모든 코드에 대해 "11로 돌리기"다이얼 만 적용 할 수 있습니다.
프로그램 실행 시간에 대한 이러한 최적화의 효과적인 결과는 종종 다른 곳에서 실행되는 코드의 영향을받습니다. 파일 읽기, dbase 쿼리 실행 등. JIT 최적화 프로그램이 완전히 보이지 않게합니다. 그래도 상관 없습니다 :)
JIT 최적화 프로그램은 수백만 번 테스트를 거쳤기 때문에 매우 안정적인 코드입니다. 릴리스 빌드 버전의 프로그램에 문제가있는 경우는 매우 드 rare니다. 그러나 발생합니다. x64와 x86 지터 모두 구조체에 문제가있었습니다. x86 지터는 부동 소수점 일관성에 문제가있어 부동 소수점 계산의 중간체가 메모리로 플러시 될 때 잘리지 않고 80 비트 정밀도로 FPU 레지스터에 유지 될 때 미묘하게 다른 결과를 생성합니다.