Share via


관리되는 실행 프로세스

관리되는 실행 프로세스에는 이 항목의 뒷부분에서 자세히 설명하는 다음 단계가 포함됩니다.

  1. 컴파일러 선택

    공용 언어 런타임에서 제공하는 장점을 이용하려면 런타임을 대상으로 하는 하나 이상의 언어 컴파일러를 사용해야 합니다.

  2. 코드를 MSIL로 컴파일

    컴파일을 하면 소스 코드가 MSIL(Microsoft Intermediate Language)로 변환되고 필요한 메타데이터가 생성됩니다.

  3. MSIL을 네이티브 코드로 컴파일

    실행 시 JIT(Just-In-Time) 컴파일러는 MSIL을 네이티브 코드로 변환합니다. 이 컴파일 중에 MSIL과 메타데이터를 검사하여 코드의 형식이 안전한지 확인하는 확인 프로세스를 코드가 통과해야 합니다.

  4. 코드 실행

    공용 언어 런타임에서는 실행을 가능하게 해주는 인프라 실행 중에 사용할 수 있는 서비스를 제공합니다.

컴파일러 선택

CLR(공용 언어 런타임)에서 제공하는 장점을 이용하려면 런타임을 대상으로 하는 하나 이상의 언어 컴파일러를 사용해야 합니다. 예를 들면, Visual Basic, C#, Visual C++, F# 또는 Eiffel, Perl, COBOL 컴파일러 같은 타사 컴파일러 중 하나를 사용해야 합니다.

이들은 다중 언어 실행 환경이기 때문에 런타임에서 다양한 데이터 형식과 언어 기능을 지원합니다. 사용하는 언어 컴파일러에 따라 사용할 수 있는 런타임 기능이 결정되며 사용자는 이러한 기능을 사용하여 코드를 디자인합니다. 런타임이 아닌 컴파일러에서 코드에 사용될 구문을 설정합니다. 다른 언어로 작성된 구성 요소에서 사용자의 구성 요소를 완전히 사용할 수 있어야 할 경우에는 사용자 구성 요소의 내보낸 형식에서 공용 언어 사양에 포함된 언어 기능만 노출해야 합니다. CLSCompliantAttribute 특성을 사용하여 코드가 CLS 규격을 따르도록 할 수 있습니다. 자세한 내용은 CLS 규격 코드 작성을 참조하십시오.

맨 위로 이동

MSIL로 컴파일

관리 코드로 컴파일할 경우 컴파일러는 소스 코드를 MSIL(Microsoft Intermediate Language)로 변환합니다. MSIL은 효율적으로 네이티브 코드로 변환될 수 있는 CPU 독립 명령 집합입니다. MSIL에는 산술 및 논리 연산, 제어 흐름, 직접 메모리 액세스, 예외 처리 및 기타 작업에 대한 명령 뿐만 아니라 로딩, 저장, 초기화 및 개체의 메서드 호출에 대한 명령도 포함됩니다. 코드를 실행하려면 대개는 JIT(Just-In-Time) 컴파일러를 사용하여 MSIL을 CPU 고유 코드로 변환해야 합니다. 공용 언어 런타임에서는 자신이 지원하는 모든 컴퓨터 아키텍처에 대해 하나 이상의 JIT 컴파일러를 제공하므로, 같은 MSIL 집합이 지원되는 모든 아키텍처에서 JIT로 컴파일 및 실행될 수 있습니다.

컴파일러에서 MSIL을 생성하면 메타데이터도 생성됩니다. 메타데이터는 모든 형식의 정의, 형식 멤버의 시그니처, 코드에서 참조하는 멤버, 실행 시 런타임에서 사용하는 기타 데이터를 포함하여 코드에 있는 형식을 설명합니다. MSIL과 메타데이터는 PE(이식 가능한 실행) 파일에 포함되어 있습니다. 이 파일은 게시된 Microsoft PE와 실행 가능 콘텐츠에 사용해왔던 COFF(Common Object File Format)를 기반으로 하며 이를 확장합니다. 메타데이터 뿐만 아니라 MSIL이나 네이티브 코드를 수용하는 이 파일 형식을 사용하면 운영 체제에서 공용 언어 런타임 이미지를 인식할 수 있습니다. 파일에 MSIL과 함께 메타데이터가 있으면 코드가 스스로 설명을 할 수 있습니다. 이것은 형식 라이브러리나 IDL(인터페이스 정의 언어)이 필요 없음을 의미합니다. 런타임은 실행 중에 필요에 따라 파일로부터 메타데이터를 찾아 추출합니다.

맨 위로 이동

MSIL을 네이티브 코드로 컴파일

MSIL(Microsoft Intermediate Language)은 공용 언어 런타임에 대해 대상 컴퓨터 아키텍처의 네이티브 코드로 컴파일해야 합니다. .NET Framework에서는 다음과 같은 두 가지 방법으로 이러한 변환을 수행할 수 있습니다.

JIT 컴파일러로 컴파일

JIT(Just-In-Time) 컴파일을 수행하면 어셈블리의 콘텐츠가 로드 및 실행될 때 응용 프로그램 런타임에서 요청 시 MSIL이 네이티브 코드로 변환됩니다. 공용 언어 런타임에서는 지원되는 모든 CPU 아키텍처에 대해 JIT 컴파일러를 제공하기 때문에 개발자는 다른 컴퓨터 아키텍처의 다른 컴퓨터에서 JIT로 컴파일하고 실행할 수 있는 MSIL 어셈블리 집합을 빌드할 수 있습니다. 그러나 관리 코드에서 플랫폼 관련 네이티브 API나 플랫폼 관련 클래스 라이브러리를 호출할 경우에는 관리 코드가 특정 운영 체제에서만 실행됩니다.

JIT 컴파일에서는 실행 중 일부 코드가 호출되지 않을 수 있다는 가능성을 고려해야 합니다. PE 파일의 모든 MSIL을 네이티브 코드로 변환하기 위해 시간과 메모리를 사용하는 대신, 실행하는 동안 필요한 MSIL을 변환하고 그 결과로 만들어진 네이티브 코드를 메모리에 저장하여 나중에 해당 프로세스의 컨텍스트에서 호출할 때 액세스할 수 있게 합니다. 형식을 로드 및 초기화하면 로더는 스텁을 만들어 형식의 각 메서드에 연결합니다. 메서드를 처음으로 호출하면 스텁은 컨트롤을 JIT 컴파일러에 전달하며, JIT 컴파일러는 해당 메서드의 MSIL을 네이티브 코드로 변환하고 스텁이 생성된 네이티브 코드를 직접 가리키도록 수정합니다. 따라서 JIT로 컴파일된 메서드에 대한 후속 호출은 네이티브 코드로 직접 전달됩니다.

NGen.exe를 사용한 설치 시 코드 생성

JIT 컴파일러는 어셈블리에 정의되어 있는 개별 메서드를 호출하면 해당 어셈블리의 MSIL을 네이티브 코드로 변환하기 때문에 런타임에 성능을 저하시킵니다. 그러나 대부분의 경우 이러한 성능 저하는 큰 문제가 되지 않습니다. 중요한 것은 JIT 컴파일러가 생성하는 코드가 컴파일을 트리거하는 프로세스로 바인딩된다는 점입니다. 이 코드는 여러 프로세스에서 공유할 수 없습니다. 생성된 코드를 여러 응용 프로그램 호출이나 어셈블리 집합을 공유하는 여러 프로세스에서 공유할 수 있도록 하기 위해 공용 언어 런타임은 사전 컴파일 모드를 지원합니다. 이 사전 컴파일 모드에서는 Ngen.exe(네이티브 이미지 생성기)를 사용하여 JIT 컴파일러와 비슷한 방식으로 MSIL 어셈블리를 네이티브 코드로 변환합니다. 그러나 Ngen.exe의 작업 방식은 다음과 같은 세 가지 면에서 JIT 컴파일러의 작업 방식과 다릅니다.

  • Ngen.exe는 응용 프로그램을 실행하는 중이 아니라 실행하기 전에 MSIL을 네이티브 코드로 변환하는 작업을 수행합니다.

  • Ngen.exe는 한 번에 하나의 메서드를 컴파일하는 것이 아니라 전체 어셈블리를 동시에 컴파일합니다.

  • Ngen.exe는 네이티브 이미지 캐시의 생성된 코드를 디스크의 파일로 유지합니다.

코드 확인

코드를 확인하는 과정을 건너뛸 수 있도록 관리자가 보안 정책을 설정하지 않은 경우에는 네이티브 코드로 컴파일하는 과정의 하나로서 MSIL 코드가 확인 프로세스를 통과해야 합니다. 확인 과정에서는 코드가 형식이 안전한지 파악하기 위해 MSIL 및 메타데이터를 검사합니다. 이 경우 액세스 권한이 있는 메모리 위치에만 액세스합니다. 형식 안정성은 개체를 서로 격리하여 실수에 의한 손상 또는 악의적인 손상으로부터 보호합니다. 형식 안정성은 코드의 보안 제한을 확실히 실행할 수 있도록 보장하기도 합니다.

런타임은 형식이 안전한지 확인된 코드의 경우 다음 문장이 참이라는 사실을 기반으로 합니다.

  • 형식에 대한 참조는 참조될 형식과 완전히 호환됩니다.

  • 개체에 대해 올바르게 정의된 작업만 호출됩니다.

  • ID가 자신이 주장하는 것입니다.

확인 프로세스 동안 MSIL 코드를 검사하여 코드에서 메모리 위치에 액세스할 수 있는지 그리고 제대로 정의된 형식을 통해서만 메서드를 호출하는지를 확인합니다. 예를 들어, 코드에서는 메모리 위치에 대한 오버런을 허용하는 방식으로 개체의 필드에 대한 액세스를 허용할 수 없습니다. 그리고 잘못된 MSIL로 인해 형식 안전성 규칙이 위반될 수 있기 때문에 확인 프로세스에서는 코드를 검사하여 MSIL이 제대로 생성되었는지 확인합니다. 확인 프로세스에서는 제대로 정의된 형식이 안전한 코드 집합만 통과시키며 형식이 안전한 코드만 전달합니다. 그러나 일부 형식이 안전한 코드는 확인 프로세스의 특정 제한 때문에 확인 과정을 통과하지 못할 수 있습니다. 그리고 일부 언어에서는 검증된 형식이 안전한 코드를 생성하지 못하도록 디자인되어 있습니다. 보안 정책에서 형식이 안전한 코드를 요구하는데 코드가 확인 과정을 통과하지 못하면 코드가 실행될 때 예외가 throw됩니다.

맨 위로 이동

코드 실행

공용 언어 런타임에서는 관리되는 실행을 가능하게 해주는 인프라 실행 중에 사용할 수 있는 서비스를 제공합니다. 메서드를 실행하려면 프로세서 고유의 코드로 컴파일해야 합니다. MSIL이 생성된 모든 메서드는 맨 처음 호출될 때 JIT로 컴파일된 다음 실행됩니다. 다음 번에 이 메서드를 실행하면 기존의 JIT로 컴파일된 네이티브 코드가 실행됩니다. 실행이 완료될 때까지 JIT 컴파일 및 코드 실행 프로세스가 반복됩니다.

실행되는 동안 관리 코드는 가비지 수집, 보안, 비관리 코드와의 상호 운용성, 다양한 언어 디버깅 지원, 확장된 배포 및 버전 관리 지원 등과 같은 서비스를 받습니다.

Microsoft Windows XP 및 Windows Vista에서는 운영 체제 로더가 COFF 헤더의 비트를 검사하여 관리되는 모듈인지 확인합니다. 비트가 설정되어 있으면 관리되는 모듈입니다. 로더가 관리되는 모듈을 발견하면 mscoree.dll이 로드되며 _CorValidateImage 및 _CorImageUnloading은 관리되는 모듈 이미지의 로드 및 언로드 시기를 로더에 알립니다. _CorValidateImage는 다음 작업을 수행합니다.

  1. 코드가 유효한 관리 코드인지 확인합니다.

  2. 이미지의 진입점을 런타임의 진입점으로 변경합니다.

64비트 Windows의 경우 _CorValidateImage는 메모리에 있는 이미지를 PE32 형식에서 PE32+ 형식으로 변환하여 수정합니다.

맨 위로 이동

참고 항목

참조

Ilasm.exe(MSIL 어셈블러)

개념

공용 언어 사양

메타데이터 및 자동 기술 구성 요소

.NET Framework 및 응용 프로그램 배포

공용 언어 런타임의 어셈블리

응용 프로그램 도메인

런타임 호스트

기타 리소스

.NET Framework의 개요

.NET Framework의 보안

비관리 코드와의 상호 운용