2. CLR! CLR! CLR!

CLR 2009. 12. 30. 09:00 Posted by 알 수 없는 사용자
CLR의 장점은 무엇일까요? 비교 대상은 CLR을 통해 생성되는 관리되는 코드(managed code)와 기존의 컴파일러로 실행 파일이 생성되는 관리되지 않는 코드(unmanaged code) 입니다.


CLR 이래서 좋다!

1. 성능 향상

CLR의 JIT 컴파일러를 통해 만들어진 코드는 unmanaged code에 비해 성능이 우수하다고 합니다. 처음 듣기에는 좀 의아한데 성능이 향상된다고 주장하는 근거는 다음과 같습니다.



a. 컴파일 시에 실행 환경에 대한 정보를 알 수 있고 이에 최적화된 지시어를 사용하여 코드를 생성합니다. (예 : 실행 환경이 펜티엄 4라고 한다면 펜티엄 4에 최적화된 지시어를 이용하여 코드를 생성하게 됩니다.)

b. 특정 상황의 테스트 값 또는 논리 연산의 결과를 실행 전에 이미 정확하게 예측할 수 있습니다.

if (numberOfCPUs > 1)
{
...
}

위와 같은 코드가 있을 경우 현재 JIT컴파일러를 통해 컴파일 될 시스템의 CPU가 하나라면 CLR의 컴파일러는 해당 if 블록이 항상 실행되지 않을 것을 알기 때문에 이 코드를 네이티브 코드로 변환하지 않습니다. 이 경우 이 실행코드는 호스팅 하는 운영체제에 최적화된 코드로 컴파일이 될 것이며 좀 더 작고 빠른 코드를 생성하게 됩니다.

c. CLR은 어플리케이션의 실행 패턴을 profile 할 수 있으며 이에 따라 실행 중에 IL코드를 네이티브 코드로 다시 컴파일 할 수 있습니다. 재 컴파일된 코드는 profile된 실행 패턴을 바탕으로 코드의 분기를 최적화하기 위해 재정렬 됩니다.

d. 일반적으로 unmanaged code는 최저사양에 맞춰 컴파일이 됩니다. 하지만 managed 코드는 실행 환경에 최적화된 코드를 생성할 수 있습니다.

저 근거들을 보면 정말 managed code가 성능면에서 봤을 때 우월하겠다는 생각이 들기도 합니다. 그런데 곰곰히 생각해보면 실제 Native Code로 컴파일하는 과정에 있어서 컴파일러가 얼마나 최적으로 컴파일을 해 내느냐가 관건일 텐데 CLR의 JIT컴파일러와 기존 비관리되는 코드를 생성해 내는 컴파일러들의 성능 비교를 해봐야 할 것입니다.

하지만 평균적으로 봤을 때 실제 실행되는 환경에 최적화된 코드를 즉시에서 뽑아내는 방식의 managed code가 좀 더 나은 코드를 만들어 낼 수 있을거라는 생각이 들기는 합니다.

2. 다른 언어로 개발된 구성 요소를 쉽게 사용할 수 있는 기능

managed code는 IL 코드와 함께 메타데이터 정보가 들어있습니다. CLR은 이 메타데이터 정보를 이용하여 클래스를 찾고 로드하며, 메모리에 인스턴스를 배치하고, 메서드 호출을 확인하고, 네이티브 코드를 생성하고, 보안을 강화하며, 런타임 컨텍스트 경계를 설정합니다. CLR을 지원하는 어떤 언어든지 컴파일을 하게 되면 동일한 IL을 생성하게 됩니다. 이러한 이유로 인해 다른 언어로 개발되었다 하더라도 구성 요소를 쉽게 사용할 수 있게 됩니다.

3. 클래스 라이브러리에서 제공하는 확장 가능한 형식

구성 요소 및 응용 프로그램에 속한 개체가 여러 언어를 통해 상호 작용하는 경우 이를 쉽게 디자인할 수 있습니다. 다른 언어로 작성된 개체들이 서로 통신할 수 있고 해당 동작들이 완벽하게 통합될 수 있습니다. 예를 들어, 클래스를 정의한 다음 다른 언어를 사용하여 원본 클래스에서 클래스를 파생시키거나 원본 클래스의 메서드를 호출할 수 있습니다. 또한 클래스의 인스턴스를 다른 언어로 작성된 클래스의 메서드로 전달할 수 있습니다. 런타임을 대상으로 하는 언어 컴파일러 및 도구에서 런타임에서 정의한 공용 형식 시스템을 사용하고, 형식의 생성, 사용, 유지 및 바인딩 뿐만 아니라 새 형식을 정의할 때도 런타임 규칙을 따르기 때문에 이러한 언어 간 통합이 가능합니다.

4. 상속, 인터페이스 및 개체 지향적인 프로그래밍을 위한 오버로딩 등과 같은 새로운 언어 기능. 확장 가능한 다중 스레드 응용 프로그램을 만들 수 있도록 해주는 명시적 자유 스레딩에 대한 지원. 구조적 예외 처리 및 사용자 지정 특성에 대한 지원.

이 부분은 이전의 unmanaged code와 비교한 장점이라기 보다는 .NET Framework 차원에서 지원하는 플랫폼 상의 새로운 기능에 대한 이야기로 보입니다. 말이 참 길고 어렵습니다. 이 부분에 대해서는 공부하면서 차차 알아가게 될 것으로 보입니다.

5. 횟수 계산이 필요 없도록 개체 수명을 관리하는 가비지 수집

기존 C/C++ 환경에서의 프로그래밍을 하던 분이시라면 가장 편리하게 생각할 것이라고 생각합니다. 예전 JAVA가 나왔을 때도 장점으로 내세웠던 부분 중 하나였지요. 이건 CLR의 장점이라기 보다는 .NET Framework 차원에서 지원하는 장점이라고 봐야 할 것 같네요. 가비지 수집기는 메타데이터를 통해 객체의 수명 상태를 조사해서 수집 대상을 확인할 수 있으며 런타임시에도 해당 객체가 포함하고 있는 멤버의 파악은 물론 이들 중 어떤 멤버가 다른 객체에 의해서 참조되고 있는지도 파악이 가능합니다.  이런 이유로 메모리 누수로 인한 문제점을 원천적으로 해결할 수 있기 때문에 프로그래밍 환경이 매우 깔끔하며 메모리 누수로 인해 시스템에 악영향을 미치지 않습니다.

7. IDL(인터페이스 정의 언어)의 필요성을 없앤 자체 설명 개체

CLR환경의 파일들은 실행파일 자체내에 모든 정의된 타입과 참조된 타입의 정보가 자세하게 기록되어 있습니다. MIDL의 경우에는 사용하기가 복잡하고 어려웠던 것이 사실이지요.

8. 한 번 컴파일하여 런타임을 지원하는 모든 CPU와 운영 체제에서 실행할 수 있는 기능

지금까지 거론된 장점들도 중요한 장점들이겠지만 이만큼 한눈에 확- 들어오는 장점이 있을까요. 한번 작성된 프로그램은 어디에서나 수정 없이 실행이 가능합니다. 다만 이 플랫폼 독립성이 윈도우 환경에만 국한된다는 점이 아쉽습니다.

9. 손쉬운 IL 컴파일러 제작 및 코드 검증

IL코드는 스택기반이며 레지스트리를 직접 제어하는 지시어를 포함하고 있지 않습니다. 그리고 IL의 모든 지시어들은 특별히 타입에 의존적이지 않습니다. (예 : IL의 ADD 지시어의 경우 32비트 또는 64비트의 경우의 ADD가 따로 존재하지 않습니다.) 그렇기 때문에 개발자는 레지스트리나 CPU에 대한 관리를 생각할 필요가 없이 비교적 손쉽게 IL코드를 생성하는 컴파일러를 만들 수 있습니다.

그리고 이 IL코드가 CPU종속적인 네이티브 코드로 전환 될 때 CLR은 검증 작업이라는 것을 수행하게 됩니다. 수행되는 메서드의 인자의 타입과 개수 체크부터 시작하여 메모리 관련 오류나 (잘못된 메모리를 읽고 쓰는 등의) 타 프로세스의 메모리에 불법적으로 접근하는 등의 문제도 검증할 수 있기 때문에 부적절한 코드의 실행을 원천적으로 차단할 수 있습니다.(이를 코드 기반 보안이라고 합니다.) CLR은 각각의 관리되는 어플리케이션을 AppDomain이라는 것으로 안전하게 관리하게 됩니다. 이로써 프로그램을 안전하고 견고하게 작성하는 것이 가능합니다.

10. 손쉬운 응용프로그램 배포

단순히 파일을 복사하는 것만으로도 설치가 가능합니다. 이전의 레지스트리에 의존하는 COM이나 DLL처럼 버전차이로 인한 문제도 없습니다.


 
CLR이 과연 좋기만 할까?

1. IL 코드 보안

IL코드는 역어셈블을 하게 되면 소스코드를 얻어내는 것이 매우 쉽습니다. 이 말은 소스코드 레벨의 보안이 어렵다는 이야기입니다. 물론 third-party 벤더에서 판매하는 암호화 처리 유틸리티등으로 좀 더 역어셈블을 어렵게 만들 수는 있습니다.

2. 다양한 언어를 지원한다는 것이 마냥 좋을 것일까?

다양한 언어를 지원하여 언어 독립성을 지켜준다는게 대규모 프로젝트 시 장점으로만 작용하는 것은 아닐거라고 생각합니다. 물론 한 프로젝트에서 3~4가지 이상의 언어가 동시에 사용되는 경우가 드물기는 하겠지만 만에 하나 사용된다고 하더라도 언어별 차이로 인한 골치 아픈 관리문제가 발생할 가능성도 큽니다. 전체 프로젝트를 관리하는 입장에서 해당 프로젝트를 후에 유지보수하게 되는 개발자가 있다면 각 언어에 대해 어느정도의 지식이 있어야 전체 프로젝트를 관리할 수 있을 것입니다. 그런데 이렇게 써놓고 보니까 좀 억지스럽기도 하네요. ㅎㅎ 프로젝트 개발 시작 시 이런 문제는 정책적으로 해결할 수 있을테니까요.

3. Native Code보다 빠릅니까?

성능 향상에 대한 근거를 앞에서 살펴보았습니다. 그런데 메모리 관리나 명령어 최적화는 납득이 가는데 정말 C/C++을 이용하여 생성된 Native Code보다 빠르게 작동할 수 있겠느냐. 라는 문제는 회의적인 입장을 가진 시각이 있습니다.

4. Framework가 깔려야 합니다.

CLR을 이용하기 위해서는 .NET Framework가 설치되어야 합니다. 요사이는 윈도우의 경우 기본적으로 .NET Framework가 설치되어 있기 때문에 크게 문제될 것은 없습니다. 하지만 계속해서 새로운 버전의 .NET Framework가 출시되고 있는터라 개발 시 그리고 배포 시 버전에 신경을 써야 합니다.



지금까지 CLR에 대해 알아보았습니다. CLR은 .NET Framework의 구성요소 중 하나입니다. 그렇다면 우리가 배워야 할 CLR을 포함하고 있는 .NET Framework에 대해서도 간략하게 살펴보아야 하겠네요.

.NET Framework는 크게 다음과 같은 요소로 구성되어 있습니다.

1)CLR(Common Language Runtime) 공통 언어 런타임

우리가 배울 놈이지요. 자바에서는 JVM이 있고 .NET에서는 CLR이 있습니다. .NET의 핵심 커널로써 .NET 프로그램 실행을 위한 모든 서비스를 제공하는 주체라고 할 수 있습니다.

2) CTS(Common Type System) 공통 타입 시스템

.NET 언어 간에 공통으로 사용되는 표준 데이터 타입입니다. 각 언어마다의 변수, 메서드, 클래스, 구조체, 인터페이스 등의 타입이 다를수 있는데, 이렇게 다른 타입을 .NET 기본 클래스에 정의한 타입으로 관리할 때 참조하는 명세서와 같습니다. 이는 어떤 언어로 프로그래밍을 하던 .NET 기본 클래스에 정의된 타입으로 매치가 가능하다는것을 나타내고 있습니다. 다시 말해, 서로 다른 언어로 작성되었다 하더라도 .Net에서 이해할 수 있는 데이터 형식인지 아닌지를 테스트하고 검증 관리하는 역할을 담당합니다. 그러므로 .Net 내에서 동작할 수 있는 데이터 형에 대한 관리를 해준다고 말할 수 있습니다.

CTS의 멤버에는 필드(Field), 메서드(Method), 속성(Property), 이벤트(Event) 가 있으며 각 타입들의 접근성에 대해서도 명시하고 있습니다. 접근성의 종류에는 Private, Family(C++이나 C#에서는 Protected로 표현됩니다.), Family & Assmebly(C#등이나 Visual Basic .NET등에서는 지원하고 있지 않습니다.), Assembly(보통 Internal이라는 키워드로 표현됩니다.), Public 이 있습니다.

3) CLS(Common Language Specification) 공통 언어 사양

.NET 용 프로그래밍 언어가 따라야 하는 공통된 최소한의 표준 규약으로, 적어도 .Net에서 동작하기 위해서는 반드시 지켜야하는 언어 스펙입니다. 모든 언어들이 다 중간언어로 변환이 가능한 것은 아닙니다. 언어마다 특성이 있어서(예를 들자면 어떤 언어는 대소문자를 구분하지 않거나, unsigned integer 같은 형식은 지원하지 않습니다. 또는 어떤 언어는 가변 인자를 지원하지만 어떤 언어는 그렇지 않습니다.), 변환이 가능한 프로그램을 작성하기 위해서는 지켜져야 할 최소한의 규칙이 있는데, 이 규칙을 모아 놓은 것이 공통 언어 사양(Common Language Specification: CLS) 입니다.



그림을 보면 CLS는 다양한 언어들 사이에서 최소한의 교집합을 가지고 있습니다. 그리고 CLR을 지원하는 언어들은 CLR/CTS환경에 속해 있는데 이를 보면 알 수 있듯이 C#이나 Visual Basic 그리고 기타 등등의 CLR을 지원하는 언어들은 100% CLR/CTS의 기능을 지원해 주지 않는 것을 알 수 있습니다. 100% 활용을 위해서는 개발자가 IL 어셈블러 언어로 코드를 작성해야 합니다.

4) BCL(Base Class Library) 기본 클래스 라이브러리
모든 언어에서 공통적으로 사용할 수 있는 방대한 클래스 라이브러리입니다. 객체 지향적이며 문서화도 잘 되어 있기 때문에 쓰기가 매우 편리합니다. 대략 다음과 같은 것들이 있습니다.

* 기본 타입 관련
* 배열, 연결 리스트, 큐 같은 컬렉션
* 그래픽 라이브러리 (GDI+)
* 스레드와 동기화 클래스
* 각종 컨트롤
* 파일 IO
* 네트워크 / 인터넷
* 데이터 베이스

FCL(Framework Class Library)라는 명칭도 있습니다. BCL(최소한의 기본적인 라이브러리 모음) + 추가 클래스 라이브러리 모음으로 BCL보다 훨씬 큰 집합입니다.


자. 지금까지 CLR의 특징부터 .NET Framework의 구조에 대해 대략 알아봤습니다. 이제 배경에 대해 어느정도 살펴 봤으니 다음부턴 본격적으로 CLR에 대해 들어가보려고 합니다. :)

현재 .NET Framework는 3.5까지 공개가 되어 있고 Visual Studio 2010에서는 .NET Framework 4.0이 포함이 되어 있습니다. 우리가 공부할 CLR의 버전도 .NET Framework의 버전을 따라 업그레이드 되고 있지요.

.NET Framework 4.0의 특징은 .NET Framework 섹션에서 아주 자세히 잘 설명이 되어 있습니다.(http://vsts2010.net/6) 꼭 읽어보세요!!!




'CLR' 카테고리의 다른 글

6. Assembly - GAC(Global Assembly Cache)  (2) 2010.02.02
5. Assembly - Strongly named assemblies  (0) 2010.01.26
4. Assembly  (2) 2010.01.15
3. MSCorLib & Metadata  (4) 2010.01.06
1. Hello 世界  (0) 2009.12.23