Managed, Unmanaged,
Native: What Kind of Code Is This?
With the release of Visual Studio .NET 2003
(formerly known as Everett) on April 24th, many developers are now
willing to consider using the new technology known as managed code. But
especially for C++ developers, it can be a bit confusing. That's because C++,
as I pointed out in my first column here, is special.
1. What Is Managed Code? –
Managed code란?
Managed Code is what Visual Basic .NET and C#
compilers create. It compiles to Intermediate Language (IL), not to machine
code that could run directly on your computer. The IL is kept in a file called
an assembly, along with metadata that describes the classes, methods, and
attributes (such as security requirements) of the code you've created. This
assembly is the one-stop-shopping unit of deployment in the .NET world. You
copy it to another server to deploy the assembly there—and often that copying
is the only step required in the deployment.
Manage
code 란 무엇인가? Managed code는 Visual Basic .NET과 C# 컴파일러가 만들어내는 것을 말한다. 이 컴파일러들은 우선 IL(Intermediate Language – 중간 언어) 라고 불리는 코드를 만들어 낸다. 이 IL은 컴파일을 수행한 당신의 컴퓨터에서 바로 실행되기 위한 machine
code (기계 언어)가 아니라는 점을 알아야 한다. 이렇게 생성된 IL은 어셈블리라고 불리는 파일에 저장되고 이때 메타 데이터도 함께 저장하는데 이 메타 데이터들은 내가 컴파일한 코드의 클래스, 함수 그리고 변수 및 속성 (보안 관련 속성도 포함)등을 가진다. 이제 이 어셈블리 파일은 .NET 세계에서 배달 완료된 모든 내용이 포장된 일종의 ‘상품’이다. 당신은 이것을 다른 서버에 복사하여 deploy (배포)하기만 하면 된다.
Managed code runs in the Common Language
Runtime. The runtime offers a wide variety of services to your running code. In
the usual course of events, it first loads and verifies the assembly to make
sure the IL is okay. Then, just in time, as methods are called, the runtime
arranges for them to be compiled to
machine code suitable for the machine the assembly is
running on, and caches this
machine code to be used the next time the method is called. (This is called Just
In Time, or JIT compiling, or
often just Jitting.)
Managed
code는 이른바 Common
Language Runtime (줄여서 CLR) 환경에서 동작한다. 이 CLR은 내가 작성한 코드가 실행될 때 다양한 형태의 서비스를 지원한다. 여기서 주의 깊게 봐야 하는 단어는 ‘실행될 때’이다. 일반적인 경우, CLR은 우선 어셈블리 파일을 읽은 다음 IL이 괜찮은지부터 확인한다. 그리고 함수가 호출되는 순간 CLR은 현재 프로그램이 돌아가는 컴퓨터의 환경에 적합한 기계 언어를 만들어 낸다. 그리고 이 함수가 다음 번에 호출되면 바로 사용될 수 있게 하기 위해서 만들어진 기계언어 코드를 cache (캐시)에 저장해 둔다. 이것이 바로 Just In
Time 혹은 줄여서 JIT 컴파일링 이라 불리는 기법이다. 여기서 중요한 것은 현재 프로그램이 돌아가는 컴퓨터 환경에 적합한 기계 언어 생성이다. 이것이 바로 CLR의 강점이다.
As the assembly runs, the runtime continues to
provide services such as security, memory management, threading, and the like.
The application is managed by the runtime.
어셈블리가 실행되는 동안 CLR은 보안, 메모리 관리, 스레딩에 관련된 서비스 일체를 제공하고 이런 프로그램을 우리는 ‘Runtime에 의해 Managed (관리되는) 프로그램이다’ 라고 한다.
Visual Basic .NET and C# can produce only
managed code. If you're working with those applications, you are making managed
code. Visual C++ .NET can produce managed code if you like: When you create a
project, select one of the application types whose name starts with .Managed.,
such as .Managed C++ application..
Visual
Basic .NET과 C#은 오직 managed 코드만 생성가능 하다. 만약 당신이 그 프로그램들을 사용한다면 당신은 managed code를 생성해 내고 있는 것이다. 반면 Visual C++ .NET은 내가 원하면 managed code를 생성할 수도 있고 아니면 unmanaged code를 생성할 수도 있다. 이것은 Visual Studio 프로젝트 속성에서 변경 가능하다.
2. What Is Unmanaged Code? – Unmanaged
code 란?
Unmanaged code is what you use to make before
Visual Studio .NET 2002 was released. Visual Basic 6, Visual C++ 6, heck, even
that 15-year old C compiler you may still have kicking around on your hard
drive all produced unmanaged code. It compiled directly to machine code that ran
on the machine where you compiled it—and on other machines as long as they had the same chip, or
nearly the same. It didn't get services such as security or memory management
from an invisible runtime; it got them from the operating system. And
importantly, it got them from the operating system explicitly, by asking for
them, usually by calling an API provided in the Windows SDK. More recent
unmanaged applications got operating system services through COM calls.
Unmanaged
code는 Visual
Studio .NET 2002가 나오기 전에 만든 코드를 말한다. 즉, Visual Basic 6, Visual C++ 6 그리고 15년 이상된 C 컴파일러 또한 Unmanaged
code를 생성해 낸다. 이것들은 내가 컴파일을 수행하는 ‘바로 그 컴퓨터’에 적합한 기계 코드를 생성해 낸다. (Managed
code 처럼 IL 생성 과정이 없다.) 고로 이렇게 생성해낸 기계 언어는 같은 칩 및 하드웨어 구성을 가지지 다른 컴퓨터에서는 돌아갈지 모르나 다른 구성을 가지는 컴퓨터에서는 당연히 실행 불가다. 또한 이렇게 생성된 unmanaged
code는 보안 및 메모리 관리 서비스를 실행시에 Runtime으로부터 받을 수가 없다. 대신
OS(Windows)로부터 받는다. 여기서 중요한 점은 OS로부터 서비스를 받기는 하지만 이것은 Windows SDK가 제공하는 특정 함수 (API)를 호출함으로써 가능하다. 근래의 Unmanaged code는 운영체제의 서비스를 COM call에 의해 제공받는다라고 했다. 이 글이 2004년 글이므로 COM을 ‘근래의 언어’라고 표현한 것이 이해가 간다. 아무튼, 요약하자면 managed code의 경우 runtime이 알아서 메모리 관리를 해주는데 반해 (Garbage collection) unmanaged code의 경우, 사용자에게 그 책임이 있다는 점이다. 다만 COM과 같이 발전된 형태의 라이브러리들은 스스로 객체의 파괴를 관리하는 능동성을 가지고는 있다.
Unlike the other Microsoft languages in Visual
Studio, Visual C++ can create unmanaged applications. When you create a project
and select an application type whose name starts with MFC, ATL, or Win32,
you're creating an unmanaged application.
다른 Microsoft
의 언어들과는 다르게 Visual
C++는 unmanaged
프로그램을 만들 수 있다. MFC, ATL
혹은 Win32 로 생성되는 프로젝트들은 모두 unmanaged
application이다.
This can lead to some confusion: When you create
a .Managed C++ application., the build product is an assembly of IL with an
.exe extension. When you create an MFC application, the build product is a Windows
executable file of native code, also with an .exe extension. The internal
layout of the two files is utterly different. You can use the Intermediate
Language Disassembler, ildasm, to look inside
an assembly and see the metadata and IL. Try pointing ildasm at an unmanaged
exe and you'll be told it has no valid CLR (Common Language Runtime) header and
can't be disassembled—Same extension, completely different files.
당연히 Visual C++로 Managed
application을 만들 수도 있다. 이때 .exe 확장자를 가지는 IL 어셈블리가 만들어진다. 만약 당신이 MFC 프로그램(unmanaged code)을 만든다면 이것은 똑같은 확장자인 .exe를 가지는 native code를 생성해 낼 것이다. 여기서 혼란이 올 수도 있다. 같은 .exe 확장자를 가지니까 뭐가 뭔지 모를 수 있다. 이 둘을 구분하기 위해서는 Intermediate Language Disassembler, 줄여서 ildasm이라 불리는 놈으로 어셈블리와 메타 데이터를 들여다 보면 된다.
Unmanaged code를 ildasm으로 보려고 하면 유효한 CLR 헤더가 없다고 에러 메시지를 출력할 것이란다. 즉, 이 두 개의 .exe 파일은 완전히 다른 형태의 파일이다.
3. What about Native Code? –
Native code란?
The phrase native code is used in two contexts.
Many people use it as a synonym for
unmanaged code: code built with an older tool, or deliberately chosen in
Visual C++, that does not run in the runtime, but instead runs natively on the
machine. This might be a complete application, or it might be a COM component
or DLL that is being called from managed code using COM Interop or PInvoke, two
powerful tools that make sure you can use your old code when you move to the
new world. I prefer to say .unmanaged code. for this meaning, because it
emphasizes that the code does not get the services of the runtime. For example,
Code Access Security in managed code prevents code loaded from another server
from performing certain destructive actions. If your application calls out to
unmanaged code loaded from another server, you won't get that protection.
Native
code는 두 가지의 의미를 가지고 있다. 우선 Native
code라 함은 Unmanaged
code의 동의어로 사용된다. 옛날 버전의 컴파일러로 컴파일 되었거나 Visual
C++에서 일부러 선택한 컴파일러에 의해 해당 컴퓨터에 적합한 기계언어의 생성을 말하며 이는 런타임시 (실행되는 순간) CLR에 의해 아무런 서비스를 받을 수 없다는 것을 의미한다. 이런 Native
code(Unmanaged code)는 하나의 완전한 프로그램 일 수도 있고, COM 컴포넌트 일 수도 있고, 혹은 Managed code내부에서 호출된 DLL일 수도 있다. 하지만 이런 경우 ‘Unmanaged
code’라고 하는 것이 더 합당한데 왜냐면 Unmanaged code라는 것이 실행시에 Runtime으로부터 서비스를 받을수 없다는 것을 분명히 강조하기 때문이란다. 예를 들어 설명한 것이 서로 다른 컴퓨터에서 실행되는 프로그램이 Managed
code인 경우 보안 관련 서비스를 실행시 (Runtime)에 받을수 있으나 Unmanaged
code의 경우 그럴 수 없다는 것.
The other use of the phrase native code is to
describe the output of the JIT compiler, the machine code that actually runs in
the runtime. It's managed, but it's not IL, it's machine code. As a result,
don't just assume that native = unmanaged.
또 다른 의미의 Native
code는 JIT 컴파일로부터 생성된 코드를 말한단다. JIT은 Managed
code에만 사용되므로 이것은 분명 Managed
code이지만 IL 코드가 아니고 해당 컴퓨터에 적합한 기계언어이다. 고로 Native라는 단어를 무조건적으로 Unmanaged라고 생각하지 말라.
Does Managed Code Mean Managed Data? –
Managed code는 Managed Data를 의미하나?
Again with Visual Basic and C#, life is simple
because you get no choice. When you declare a class in those languages,
instances of it are created on the managed heap, and the garbage collector
takes care of lifetime issues. But in Visual C++, you get a choice. Even when
you're creating a managed application, you decide class by class whether it's a
managed type or an unmanaged type. This is an unmanaged type:
Visual
Basic이나 C#을 사용한다면 모든 것이 Managed code이므로 오히려 간단하다. 고로 내가 만약 그 언어들을 사용해서 프로그램을 작성한다면, 클래스를 하나 선언하고 객체화를 했을 때 이 객체는 Managed Heap에 생성되고 Garbage Collector가 알아서 메모리를 수거해 간다. 하지만 내가 만약 Visual C++를 사용한다면 나는 각각의 클래스를 선언할 때 마다 선택을 할 수가 있게 된다. 이른바 클래스가 Managed type인가 아니면 Unmanaged type인가를 다음과 같이 결정한다. 우선 Unmanaged type의 경우 다음과 같이 선언한다.
class Foo
{
private:
int x;
public:
Foo():
x(0){}
Foo(int xx): x(xx) {}
};
This is a managed type:
그리고 Managed
type의 경우 다음과 같다.
__gc class Bar
{
private:
int x;
public:
Bar():
x(0){}
Bar(int xx): x(xx) {}
};
The only difference is the __gc keyword on the definition of Bar. But it makes a huge
difference.
차이점이라고는 클래스 선언 앞부분에 __gc가 붙냐 안붙냐 차이 밖에 없다. 하지만 그 차이는 엄청나다.
Managed types are garbage collected. They must
be created with new, never on the stack. So this line is fine:
Managed
type는 garbage
collector에 의해 자동으로 메모리가 수거 된다. 고로 이 놈들은 반드시 new를 이용해서 생성해야 하며 절대로 stack에 생성될 수 없다. 고로 위에 Unmanaged type으로 생성한 Foo 클래스의 경우 위 명령처럼 스택에 선언할 수 있지만,
But this line is not allowed:
Managed
type으로 선언한 Bar 클래스의 경우 Foo 클래스와 같은 방식으로 스택에 선언 할 수가 없다.
If I do create an instance of Foo on the heap, I
must remember to clean it up:
Foo* pf = new Foo(2);
// . . .
delete pf;
The C++ compiler actually uses two heaps, a
managed an unmanaged one, and uses operator overloading on new to decide where
to allocate memory when you create an instance with new.
만약 내가 Foo 클래스를 힙에 선언한다면 (다른 말로 포인터 생성하여 new로 객체화 할 경우), 반드시 메모리 삭제를 delete를 통해서 파괴해야 한다. C++ 컴파일러는 실제로 두개의 힙을 사용하는데 각각은 managed와 unmanaged를 위한 것이다. new 라는 키워드는 오버로딩을 통해서 managed와 unmanaged
힙 중에 하나를 선택하여 메모리 할당한다.
If I create an instance of Bar on the heap, I
can ignore it. The garbage collector will clean it up some after it becomes
clear that no one is using it (no more pointers to it are in scope).
There are restrictions on managed types: They
can't use multiple inheritance or inherit from unmanaged types, they can't
allow private access with the friend keyword, and they can't implement a copy
constructor, to name a few. So, you might not want your classes to be managed
classes. But that doesn't mean you don't want your code to be managed code. In
Visual C++, you get the choice.
반대로 만약 내가 Bar 클래스를 힙에 생성하면 나는 간단히 신경 끄면 그만이다. 왜? Garbage
collector가 알아서 메모리를 수거할 테니…
단, managed
type에는 몇가지 제약이 있으니 바로 다중 상속이 안되며 unmanaged
type으로 부터의 상속이 안된다는 제약이다. 또한 private 속성에 대한 접근이 friend 키워드를 통해서도 안되고, 복사 생성자를 구현 할 수가 없단다. 요런 저런 제약을 보아하니 아마도 당신은 managed
class를 만들고 싶지 않을 수도 있다. 하지만 그것이 당신의 프로그램 전체가 managed code가 아니길 바란다는 것은 아닐 것이다 (managed와 unmanaged를 섞어 써도 된다는 말). 암튼, C++에서는 프로그래머가 선택할 수 있다.
결론만 말하자면,
2. Managed code는 CLR에 의해 해당 컴퓨터에 적합한 기계 언어를 능동적으로 생성하여 범용성을 높였다.
3. Unmanaged code는 실행시의 CLR이 제공하는 서비스를 제공받을 수 없다.
4. Unmanaged code는 컴파일할때 컴퓨터의 환경에 적합한 기계어만 생성하므로 범용성이 매우 낮다.
5. Native code는 '기계 언어'라고 보는 것이 적합하며 Native code를 Unmanaged code라고 생각하면 안된다.
6. Visual C++는 Managed Type과 Unmanaged Type의 클래스를 생성할 수 있다.
7. Managed Type 클래스는 힙에 생성되면 자동으로 메모리 수거가 이루어 지는 반면 Unmanaged Type 클래스는 사용자가 수거해야 한다.
8. __gc를 클래스 선언시 사용하면 Managed Type 클래스를 선언 할 수 있다.
About the Author
Kate Gregory is a founding partner of Gregory Consulting Limited (www.gregcons.com).
In January 2002, she was appointed MSDN Regional Director for Toronto, Canada.
Her experience with C++ stretches back to before Visual C++ existed. She is a
well-known speaker and lecturer at colleges and Microsoft events on subjects
such as .NET, Visual Studio, XML, UML, C++, Java, and the Internet. Kate and
her colleagues at Gregory Consulting specialize in combining software
develoment with Web site development to create active sites. They build quality
custom and off-the-shelf software components for Web pages and other
applications. Kate is the author of numerous books for Que, including Special Edition Using Visual C++ .NET.
'프로그래밍' 카테고리의 다른 글
프로그램의 원리 (컴파일, 링크, DLL) (0) | 2010.03.11 |
---|---|
유니코드 (Updated!) (4) | 2010.03.06 |
Finding Convex Hull (Graham's Scan) - 외곽선 찾기, 임의의 사각형 내부에 임의의 점 존재 확인 (8) | 2010.02.18 |
객체 지향의 이해 1 - 클래스 (0) | 2009.12.19 |
x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.4053_x-ww_e6967989 (6) | 2009.09.10 |