... | ... | @@ -4,16 +4,7 @@ |
|
|
.NET Framework는 MS에서 2000년 6월에 발표한 응용 프로그램 개발 환경이다.
|
|
|
각종 응용 프로그램을 작성 및 실행 해주는 걸 도와줌으로써 개발자가 응용 프로그램의 비즈니스 코드에만 집중할 수 있게 도와준다.
|
|
|
소프트웨어를 어느 곳에서나 수정 없이 쓰려면 호환성의 문제를 해결해야 한다. .NET은 다양한 운영체제에서 작동하는 호환성을 목표로 만들어졌으며,
|
|
|
웹 상의 어느 곳에서나 실행 가능한 프로그램을 작성하는 것이 .NET의 궁극적인 목표이다. 그래서 중간 언어와 JIT 컴파일러를 통해 플랫폼 독립성을 확보하고 언어의 상호 운용이 가능하다는 장점이 있지만 그와 동시에 2번의 컴파일을 거치기 때문에 속도가 떨어진다는 단점이 공존한다.
|
|
|
|
|
|
<br />
|
|
|
|
|
|
>>>
|
|
|
**JIT 컴파일러?**
|
|
|
managed code의 소스코드는 각 언어의 컴파일러에 의해서 IL코드와 실행에 필요한 정보들을 갖고 있는 메타데이터로 이루어진 managed module로 생성 된다.
|
|
|
|
|
|
이 모듈이 실행될 경우 JIT컴파일러에 의해 실행에 필요한 부분이 곧바로 Native code로 컴파일되어 실행된다. 당연히 매번 실행시마다 JIT컴파일러에 의해 컴파일되어 실행되는 것은 아니고 한번 컴파일 된 부분은 재 사용하는 등의 최적화 과정을 통해 CLR의 코드는 실행된다.
|
|
|
>>>
|
|
|
웹 상의 어느 곳에서나 실행 가능한 프로그램을 작성하는 것이 .NET의 궁극적인 목표이다. 그래서 중간 언어와 JIT 컴파일러를 통해 플랫폼 독립성을 확보하고 언어의 상호 운용이 가능하다는 장점이 있지만 그와 동시에 2번의 컴파일을 거치기 때문에 속도가 떨어진다는 단점이 공존한다.
|
|
|
|
|
|
<br />
|
|
|
.NET의 계층구조는 다음과 같다.
|
... | ... | @@ -48,76 +39,40 @@ CLR(Common Language Runtime)은 CLI 사양을 따르는 가상 머신이다. CLT |
|
|
여기서 가장 주 된 업무인 1번과 2번이다.
|
|
|
|
|
|
1번 업무인 IL 코드를 기계어로 컴파일하는 것은 CLR 내의 JIT(Just In Time) 컴파일러가 담당한다. CLR과 CLS의 존재로 인해서 .NET 호환 언어에 한해서 언어의 종류에 구애받지 않고 .NET Framework를 기반으로 작동하는 프로그램을 만들 수 있다.
|
|
|
<br />
|
|
|
2번 업무인 동적 메모리 관리는 가비지 컬렉터가 담당한다. C 또는 C++로 프로그래밍을 하다보면 메모리 관리때문에 복잡한 경우가 많은데, C#에서는 가비지 컬렉터가 메모리 관리를 대신해주기 때문에 편하게 프로그래밍을 할 수 있다.
|
|
|
하지만 이 가비지 컬렉터 또한 CPU와 메모리를 사용하기 때문에 가비지 컬렉터가 최소한으로 자원을 사용하게 한다면 프로그램의 성능을 높일 수 있다.
|
|
|
가비지 컬렉터의 메커니즘을 파악하면 프로그래밍을 할때의 코딩지침을 세울 수 있다.
|
|
|
<br />
|
|
|
**가비지 컬렉터의 작동 메커니즘**
|
|
|
C#으로 작성한 프로그램을 실행하면 CLR은 프로그램을 위한 일정 크기의 메모리를 확보한다. C-runtime 처럼 메모리를 쪼개는 일을 하지 않고 그냥 일정 메모리 공간을 확보해서 하나의 관리되는 힙(Managed Heap)을 마련한다.
|
|
|
객체를 할당하게 되면 메모리에 순서대로 할당하게 된다.
|
|
|
|
|
|
참조 형식의 객체가 할당될 때는 스택 영역에는 힙의 메모리 주소를, 힙 영역에 실제 값이 할당된다.
|
|
|
그럼 객체가 할당된 코드블록이 끝나면 스택 영역의 메모리가 회수되고, 힙 영역의 값을 참조하던 객체가 사라졌으므로 그 값은 쓰레기가 된다.
|
|
|
여기서 회수된 스택의 객체를 루트(Root) 라고 부른다.
|
|
|
.NET 응용 프로그램이 실행되면 JIT 컴파일러가 이 루트들을 목록으로 만들고 CLR은 이 루트 목록을 관리하며 상태를 갱신하게 된다.
|
|
|
방법은 다음과 같다.
|
|
|
|
|
|
>>>
|
|
|
가비지 컬렉터는 힙영역의 임계치에 다다르게 되면
|
|
|
1. 모든 객체가 쓰레기라고 가정한다.( 루트 목록 내의 어떤 루트도 메모리를 가리키지 않는다고 가정 )
|
|
|
2. 루트 목록을 순회하면서 참조하고 있는 힙 객체와의 관계 여부를 조사한다. 즉 어떤 루트와도 관계가 없는 힙의 객체들은 쓰레기로 간주된다.
|
|
|
3. 쓰레기가 차지하고 있던 메모리가 회수되면, 인접 객체들을 이동시켜 차곡차곡 채워서 정리한다.
|
|
|
>>>
|
|
|
>**JIT 컴파일러?**
|
|
|
>managed code의 소스코드는 각 언어의 컴파일러에 의해서 IL코드와 실행에 필요한 정보들을 갖고 있는 메타데이터로 이루어진 managed module로 생성 된다.
|
|
|
|
|
|
CLR의 메모리도 구역을 나누어 메모리에서 빨리 해제될 객체와 오래 있을 것 같은 객체를 따로 담아 관리한다.
|
|
|
구체적으로 CLR은 메모리를 0세대, 1세대, 2세대 3가지로 분리하고, 0세대는 빨리 사라질 객체, 2세대는 오래 남아있을 것 같은 객체들을 위치시킨다.
|
|
|
그 방법은 다음과 같다.
|
|
|
|
|
|
>>>
|
|
|
응용 프로그램을 실행하면 0세대부터 할당된 객체들이 차오르기 시작한다.
|
|
|
1. 0세대 가비지 컬렉션 임계치에 도달하면 0세대에 대해 가비지 컬렉션을 수행한다. 여기서 살아남은 객체는 1세대로 옮겨진다.
|
|
|
2. 1번 과정을 계속 반복하다보면, 1세대 가비지 컬렉션이 임계치에 도달하게 되고, 1세대에 대해 가비지 컬렉션을 수행한다. 여기서 살아남은 객체는 다시 2세대로 옮겨진다.
|
|
|
3. 2번 과정도 지속되다보면 2세대 가비지 컬렉션이 임계치에 도달한다.
|
|
|
2세대 가비지컬렉션이 임계치에 도달하면 0,1,2 세대 전체 가비지컬렉션(Full Garbage Collection) 을 수행한다.
|
|
|
>>>
|
|
|
>이 모듈이 실행될 경우 JIT컴파일러에 의해 실행에 필요한 부분이 곧바로 Native code로 컴파일되어 실행된다. 당연히 매번 실행시마다 JIT컴파일러에 의해 컴파일되어 실행되는 것은 아니고 한번 컴파일 된 부분은 재 사용하는 등의 최적화 과정을 통해 CLR의 코드는 실행된다.
|
|
|
|
|
|
|
|
|
<br />
|
|
|
|
|
|
프로그램이 오래 살아남는 객체들을 마구 생성하면, 2세대 힙이 가득차게 될 것이다.
|
|
|
2세대 힙이 가득차게 되면 CLR은 응용프로그램의 실행을 멈추고 전체 가비지 컬렉션을 수행하면서 메모리를 확보하려 하기 때문에 응용 프로그램이 차지하는 메모리가 많을 수록 프로그램이 정지하는 시간도 그만큼 늘어나게 된다.
|
|
|
|
|
|
2번 업무인 동적 메모리 관리는 가비지 컬렉터가 담당한다. C 또는 C++로 프로그래밍을 하다보면 메모리 관리때문에 복잡한 경우가 많은데, C#에서는 가비지 컬렉터가 메모리 관리를 대신해주기 때문에 편하게 프로그래밍을 할 수 있다.
|
|
|
하지만 이 가비지 컬렉터 또한 CPU와 메모리를 사용하기 때문에 가비지 컬렉터가 최소한으로 자원을 사용하게 한다면 프로그램의 성능을 높일 수 있다.
|
|
|
가비지 컬렉터의 메커니즘을 파악하면 프로그래밍을 할때의 코딩지침을 세울 수 있다.
|
|
|
<br />
|
|
|
|
|
|
**코딩지침**
|
|
|
가비지 컬렉터의 메커니즘을 바탕으로 효율적인 코드를 작성하기 위한 방법이 있다.
|
|
|
|
|
|
>>>
|
|
|
- 객체를 너무 많이 할당하지 않는다.
|
|
|
* 필요 이상의 객체들이 생성되면 가비지 컬렉션이 자주 일어난다.
|
|
|
- 너무 큰 객체 할당을 피한다.
|
|
|
* CLR은 85KB 이상의 대형 객체를 할당하기 위한 대형 객체 힙 (Large Object Heap ; LOH) 을 따로 유지한다. LOH는 해제된 공간을 인접 객체가 채우는 것이 아니라 그대로 둔다. 대형 객체는 복사하여 옮기는 비용이 비싸기 때문이다. 이로 인해 큰 공간 사이사이의 메모리 조각이 SOH에 비해 많이 발생하게 된다.
|
|
|
- 너무 복잡한 참조 관계는 만들지 않는다.
|
|
|
* 참조 관계가 많은 객체는 가비지 컬렉션 후에 살아남았을 때가 문제다. 살아남은 객체는 세대를 옮기기 위해서 메모리 복사를 진행하는데, 참조 관계가 복잡할 경우 객체를 구성하고 있는 각 필드 객체간의 참조관계를 다 조사해서 메모리 주소를 수정해야하기 때문에 탐색과 수정의 오버헤드가 발생한다.
|
|
|
- 루트를 너무 많이 만들지 않는다.
|
|
|
* 가비지 컬렉터는 루트 목록을 돌면서 쓰레기를 수거하기 때문에 적을 수록 성능에 유리하다.
|
|
|
>>>
|
|
|
|
|
|
<br />
|
|
|
|
|
|
**CLR이 중요한 이유 :**
|
|
|
**CLS가 주는 호환성에 대하여**
|
|
|
그 어떤 .NET 호환 언어를 사용해서 코드를 작성하더라도, CLS 규격을 만족한다면 다양한 언어의 결과물 끼리 상호 호출이 가능하다. 컴파일러가 IL코드로 변환하여 CLR에서 실행하기 때문이다. CLR은 윈도우용 CLI 구현체이고, 리눅스의 경우에는 Mono를 쓴다. CLS 규격을 만족한다면 플랫폼 독립적인 IL코드로 변환하여 각 플랫폼의 CLI구현체를 거쳐 다양한 플랫폼에서 작동하는 프로그램을 만들 수 있다.
|
|
|
|
|
|
# 수정필要
|
|
|
### CTS
|
|
|
CTS(Common Type System)은 .NET 호환 언어들이 지켜야 할 Type과 표준 규격을 정의한 것이다.
|
|
|
CTS는 닷넷 프레임워크에 쓴이는 데이터 타입들의 정의와 쓰임에 대한 표준이다. CTS는 언어 간 통합을 용이하게 하기 위해 사용 및 관리되는 데이터 타입 모음을 정의한다.
|
|
|
CTS는 .NET 응용 프로그램, 구성 요소 및 컨트롤이 다른 프로그래밍 언어로 구축되어 정보가 쉽게 공유되는 .NET Framework의 타입을 제공합니다.
|
|
|
C와 C++에서 자주 사용되는 사용자 정의타입의 클래스나 구조체( ex. date, time)를 CTS가 제공해준다. CTS는 코드에 직접 헤더파일이나 라이브러리를 포함 할 필요없이 자주 사용되는 다양한 타입들을 사용할 수 있다.
|
|
|
CTS에서 정의하는 모든 타입은 System.Object에서 파생되도록 설계되었다.
|
|
|
|
|
|
CTS에는 값 형식(Value Type)과 참조 형식(Reference Type)이 있다.
|
|
|
|
|
|
>>>
|
|
|
* 값 형식 : 값을 변수에 넣는 데이터 형식
|
|
|
* 참조 형식 : 변수에 대한 위치(메모리 위치)를 담는 데이터 형식
|
|
|
>>>
|
|
|
CTS에는 값 타입(Value Type)과 참조 타입(Reference Type)의 2가지 타입이 있다.
|
|
|
|
|
|
>* 값 타입 : 값을 변수에 넣는 데이터 형식 -> 스택에 저장
|
|
|
>* 참조 타입 : 변수에 대한 위치(메모리 위치)를 담는 데이터 형식 -> 힙과 스택에 저장. GC가 일어나는 원인!
|
|
|
|
|
|
|
|
|
<br />
|
|
|
- - -
|
|
|
|
|
|
<br />
|
... | ... | @@ -178,22 +133,3 @@ C#, Visual Studio, .NET과의 버전 간의 상관 관계는 다음과 같다. |
|
|
|2015년 7월|C# 6.0 | .NET Framework 4.6 | Visual Studio 2015 |
|
|
|
|
|
|
// 문장이 어색한지 다시 한 번 점검, 책 다시 리뷰하면서 흐름상 중요한 부분 삽입. |
|
|
|
|
|
```csharp
|
|
|
using System;
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
namespace Ex_2_4
|
|
|
{
|
|
|
class Program
|
|
|
{
|
|
|
static void Main(string[] args)
|
|
|
{
|
|
|
|
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
|
TimeSpan time;
|
|
|
String str = String.Empty;
|
|
|
|
|
|
stopWatch.Start();
|
|
|
```
|
|
|
|