1. 앞으로 밥 먹고 살게 해줄 C#에 대해 알아보자
- 난 뭘 정리하고 싶었을까?-
DevRookie 2015. 5. 30
신동찬
2. 오늘의 주요 전달 내용
C# 프로그램은 어떤 과정으로 돌아가는가?
개발에 유용한 프로그램(IDE 아님)
C# 프로그램의 메모리 사용
.NET의 GC
.NET의 ThreadPool 동작 및 Algorithm
C# 표준 질의 연산자
3. 이번 시간 주요 안전달 내용
C# Syntax
다중 스레딩 프로그래밍 / 스레드 동기화
lambda 표현식
Reflection / Attribute
IEnumerable<t> / IEnumerator<T> 구체적 내용
(LINQ / 질의식)
빠진 내용에 대해 꽤 많이 커버하는 글
http://hyunjong-lee.github.io/tech/2015/01/17/CSharp-Basic.html
14. CLI(Common Language Infrastructure)
가장 큰 의미 단위
C# 언어에 대한 국제 규격을 구체화 한 것
.NET Framework, Unity의 Mono 등이 CLI의 각 구현임
각 구현에서는 별도의 개별 CLI와 컴파일러를 구현 했기에 서로 동일하지 않을 수 있음
CLI 표준에 포함되는 사양
• Virtual Execution System (VES, A.K.A 런타임)
• Common Intermediate Language (CIL, 공용 중간 언어)
• CTS(공용 형식 시스템)
• CLS(공용 언어 사향)
• 메타데이터 등
15. CIL(Common Intermediate Language)
속칭 IL Code
C# 컴파일러가 만들어 내는 중간 언어로 ‘런타임’이 이해할 수 있는 언어
CLR(Common Language Runtime)
가상 실행 시스템(VES)를 .NET에서는 CLR로 이름 붙임
CIL 코드를 읽어 기계어로 변환해 프로세서가 해석하도록 함
추가로 여러 서비스(보안, GC 등) 제공
CIL, VES 등등은 사양이 국제 표준에 포함
16. 이 전체가 CLI
CIL
CLR(VES)
코드와 리소스는 어셈블리로 저장
어셈블리는 형식, 버전, 문화권, 보안 등을 메니페스트에 포함
C# 프로그램이 실행되면
1. 어셈블리(exe or dll)이 CLR로 로드
2. CLR은 매니페스트를 읽어 작업을 시작
(이때 보안 요구사항을 확인)
3. JIT(Just In Time) 컴파일 수행
CLR은 실행 환경에 맞춰 기계어로 변경
4. 프로그램 작동
17. JIT Compiler
IL code상 method를 native code로 컴파일해 Memory에 올리는 작업 수행
상세 동작
프로그램 시작에 필요한 것을 변환해 메모리에 올림
이후 메모리 상황에 따라서 code를 썼다가 지웠다 함
다시 쓰는 경우 컴파일도 다시 진행해 memory에 올림 (중간 컴파일)
회피
미리 compile해 local disk에 전체 native code를 저장할 수 있음
NGEN으로 컴파일 하면 precompiled managed executable이 생성
*주의*
실행 시 반드시 original IL code를 같이 둬야 함
실행권한 확인 시 original code 권한을 확인해 결정
24. Heap 메모리를 대상으로 합니다.
Stack은 Stack 되감기로 그때그때 잘 정리하는 착한 친구
Heap은...
<한 때 유명했던 배틀필드 메모리 릭 스샷들>
25. C# 프로그램을 실행하면 4개의 Heap 공간을 생성
Process Heap: .Net Framework 수행을 위한 공간
JIT Code Heap: JIT 컴파일 결과물(native code) 저장
Small Object Heap: GC Managed Heap
Large Object Heap: GC Managed Heap
각 목적이 분명한 만큼 의문의 여지가 없음
개발 시 사용되는 것은 ObjectHeap
26. 문제는 Stack에서 사용할 데이터와 Heap에서 사용할 데이터를
어떻게 구분하는 것인가 인데
분명한 Rule이 있다
Reference 타입은 항상 heap에 생성
Value 타입은 해당 타입이 선언된 곳에서 생성
28. public class MyInt
{
public int MyValue;
}
public MyInt AddFive(int pValue)
{
MyInt result = new MyInt();
result.MyValue = pValue + 5;
return result;
}
33. GC가 인스턴스 종료자 호출을 담당
종료자가 실행되는 시기를 컴파일 타임에 정확히 결정하지 못 함
프로그래머가 명시적으로 호출 할 수도 없음
하지만
Using 구문, IDisposable 인터페이스를 사용하면
어느 정도 타이밍을 만들어 낼 수 있다
어느 정도가 포인트다.
34. {
Font font1 = new Font(“Arial”, 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
{
using (Font font3 = new Font(“Arial”, 10.0f), font4 = new Font(“Arial”, 10.0f))
{
// use font3, font4
} // 빠져나오며 Dispose 진행
}
이 두 코드는 동일하다
35. IDisposable 패턴을 위해 구현되는 Dispose() 에서는 다음 메소드를 호출
이로서 무조건 적인 삭제는 일단 거부
System.Gc.SuppressFinalize(this);
다시 한 번!
이 메소드의 효과는 GC를 막는 것이 아님!
특정 종료 메소드가 호출될 때까지 지연하는 목적
f-reachable 대기열에서 제외하는 것을 의미
37. GC 동작은 Worker Thread에 의해서 진행 됩니다.
여기서 잠깐!
CLR 의 Thread 들
• Finalizer Thread
• 죽은 heap object에 대해 finalizer를 수행하는 역할
• 한 개의 thread가 모든 finalizer를 대표
• Debugger Helper Thread
• Concurrent GC Thread
• 멀티 프로세스 PC에서 사용하는 GC
• 각 CPU마다 각각의 GC heap을 만들고
• 하나의 thread가 모든 heap을 돌며 GC를 수행하도록 함
• App Domain Unload Helper Thread
• App Domain은 CLR에서 각 응용 프로그램 간 격리를 제공하기 위한 처리 단위
• App Domain을 unload하는 명령어를 받는 경우 해당 작업 수행
• 전체 프로세스를 중지하지 않고 개별 응용 프로그램만 중지하도록 하는 등에 사용
• ThreadPool Threads
• ThreadPool 클래스에 의해 관리되는 Thread 들
38. 작업 중에 트리거된 Thread에 의해서 수행
모든 작업이 Freeze
과연 무슨 일을 하기 때문에?
39. GC 동작 과정
1. 메모리가 부족한 경우 GC 트리거링
2. ROOTS부터 순회 시작
3. 참조가 이뤄지고 있는 객체에 대한 Graph 작성
4. 객체간 참조에 대한 내용도 참조 그래프 추가
5. 도달 가능한 모든 객체를 ‘재귀’적으로 순회
이때, 모든 객체를 한 번 씩만 순회하여 최적화
Circle이 생기지 않는 그래프를 그려냄
6. 순회 과정에 죽은 오브젝트를 만나면 객체를 Finalize Queue로
결과적으로 Managed Heap에서 해제
7. Garbage Compaction 수행
8. Application 영역에서 참조하고 있는 객체간 참조 포인터 수정
9. 다음 메모리 생성 위치를 가리키는 NextObjPtr 업데이트
41. 수명이 긴 개체와 짧은 개체를 나눠 처리
수명이 짧은 개체의 공간을 적게 두고 짧은 개체의 회수를 주로 수행
이것을 모든 대상으로 매번 하지 않기 위해
GC Generation(세대) 개념을 도입
0 세대
가장 젊은 세대이며 수명이 짧은 개체
대형 개체는 2세대 수집의 대형 개체로 바로 이동
대부분의 대체는 0세대 가비지 수집에서 회수
1세대 : 0세대와 2세대의 버퍼 역할
2세대 : 수명이 길고 크기가 큰 개체
2세대 가비지 수집은 모든 세대의 모든 개체를 회수(전체 가비지 수집)
=> 여기를 막는 노력이라도 해야된다
42. Concurrent GC
GC 가 동작하는데 뭔가 슬슬 움직인다?!
워크스테이션 GC에서 Concurrent GC를 활성화 가능
이 옵션은 2세대 GC에만 영향
0세대, 1세대는 매우 빠르게 완료 되므로 항상 비동시 수집
GC 동안 할당이 가능하므로 작업 규모는 비동시 보다 약간 더 큼
CPU와 메모리도 더 많이 소비
43. 비동시 GC 부하를 줄이는 법은?
포인터가 너무 많은 데이터 구조를 만들지 말 것
많은 개체 쓰기가 존재
해당 데이터를 GC는 전부 탐색한다
(그 과정에서 포인터 모두 변경 가능...)
메모리 루트가 너무 많으면 안 됨
스택에서 유지하는 개체 포인터는 루트
빠른 순회를 위해 루트가 많지 않아야 함
가능한 한 적은 개체를 할..
45. 여기서 잠깐!
CLR 의 Thread 들
• Finalizer Thread
• 죽은 heap object에 대해 finalizer를 수행하는 역할
• 한 개의 thread가 모든 finalizer를 대표
• Debugger Helper Thread
• Concurrent GC Thread
• 멀티 프로세스 PC에서 사용하는 GC
• 각 CPU마다 각각의 GC heap을 만들고
• 하나의 thread가 모든 heap을 돌며 GC를 수행하도록 함
• App Domain Unload Helper Thread
• App Domain은 CLR에서 각 응용 프로그램 간 격리를 제공하기 위한 처리 단위
• App Domain을 unload하는 명령어를 받는 경우 해당 작업 수행
• 전체 프로세스를 중지하지 않고 개별 응용 프로그램만 중지하도록 하는 등에 사용
• ThreadPool Threads
• ThreadPool 클래스에 의해 관리되는 Thread 들
46. 작업에는 Thread가 필요하고
해당 Thread는 Thread Pool에서 나온다
Thread가 과도하게 많으면?
Context Switching은 순수 OverHead!
가상 메모리 스레싱, Convoying 등등 따라오는 문제 투성이
적절한 수의 Thread를 유지하는 것이 필요함
47. .NET의 Thread Pool은 2종류의 Sub ThreadPool로 구성
I/O Sub Pool Worker Pool
Maximum 1000 개
Overlapped I/O 작업을 처리하는 thread
(IOCP 작업 등 네트워크는 얘에게로!)
Windows의 “non-I/O thread”와 동일
(작명이 문제! 윈도우의 I/O thread는 APCs를 의미
ex) ReadFileEx...)
Maximum cpucore * 250 개
(테스트 결과 이거도 틀리다는 의견이 있음)
(시스템 환경에 맞춰 임의로 설정하며 deadlock 방지에 충분한 수)
Kernel object가 신호를 주면 해당 특정 task를 실행
그야말로 일하는 Thread, 우리가 아는 그녀석
48.
49. Worker Thread 생성 정리하면
ThreadPool Global Queue 가 있고 여기에 task가 들어옴
ThreadPool에서 Thread 생성
SetMinTreads에서 설정한 개수까지 별도의 평가 없이 계속 생성
Thread 개수가 SetMinThread에 도달하면 생성 알고리즘을 적용
Thread 작업에 답답함을 느끼고 싶지 않다면
컴퓨팅 파워를 잘 확인(실험적이든)해서 Min Thread를 조정
50. Worker Thread 소멸
MinThread 설정 값보다 더 떨어지지 않음
thread task가 종료되고 ‘Work Strealing’도 일어나지 않으면
Thread는 Thread Pool로 돌아가 대기 상태가 됨
Thread 수가 Minimum보다 많은데 대기 thread가 많다면,
특정 조건에 따라 Thread를 Terminate
Thread 작업에 답답함을 느끼고 싶지 않지만,
컴퓨팅 파워를 아껴야 한다면 적절한 MinThread 세팅이 필수
51. Worker Strealing?
말 그대로 놀고 있는 Thread가 업무를 훔쳐온다
Worker Thread는
Global Queue에서 각 Thread Queue로 옮겨진 업무를
수행하는데 불균형이 생길 수 있음
이때 다른 Thread의 업무를 가져와 수행
Queue에 대한 경함이 발생할 수 있지 않나?
Lock-Free Deque를 Thread Queue로 사용하면 경합 해결
53. Q1. Windows에서 실행하는 .NET과 다른 플랫폼에서의 .NET 차이가 있나요?
차별 대우 존재...
OS에서 지원을 못하는 걸 어쩌나...
I/O Thread 관련 함수에서 꽤 발견할 수 있음
재미있는 건 요새 좀 바뀌었음
54. Q2. GC가 돌면 메모리 삭제가 완전히 된 것이다?
그러면 안되겠지만...
무섭게도 개체 되살리기가 되는 경우가 있음
개체 종료 메소드가 호출될 즈음에 모든 참조가 사라짐
그런데 루트 참조 그래프 종료 개체에 대한 참조를 실수로 다시 추가할 수 있다?!
이렇게 추가 된 것은 더 이상 접근이 불가능하므로 가비지 수집 대상이 되지 않는다
종료 코드를 복잡하게 하면 이런 문제가 발생할 수도...
56. Q3. 식지 않는 떡밥 LINQ vs LOOP
<출처: http://zmeun.tistory.com/90>
국내에서 몇몇 발견되는 글
LINK가 For문 보다 빠르다!
57. Q3. 식지 않는 떡밥 LINQ vs LOOP
LINQ가 뭔데요?
자료 구조를 SQL 하듯이 다룰 수 있는 지원 인터페이스
쿼리 형태로 데이터를 처리 할 수 있음
1. 데이터를 획득한다
2. 쿼리를 생성한다
3. 쿼리를 실행한다
static void Main(string[] args)
{
List<int> intList = new List<int>() { 1, 2, 3, 4, 5 };
var numberMatchResult =
from num in intList
where num == 4
select num;
foreach (var num in numberMatchResult)
{
Console.WriteLine("{0}", num);
}
Console.ReadKey();
}
58. Q3. 식지 않는 떡밥 LINQ vs LOOP
사실 각 Collection이 제공하는 표준 질의 연산자도 같은 기능을 하고 있습니다.
Select, Where 등등의 연산자들...
var numberMatchResult = intList.Where(_ => _ == 4).Select(_ => _);
foreach (var num in numberMatchResult)
{
Console.WriteLine("{0}", num);
}
근데 뭔가 이상하지 않나요?
뒤에 foreach 문이 왜 따라다니죠?
59. Q3. 식지 않는 떡밥 LINQ vs LOOP
LINQ 구분의 Return 형은
IEnumerable<t>
그 자체로 값이 아니라 식일 뿐
실제로 수행을 하는 것은 쿼리를 실행하는 단계입니다.
(여기서는 foreach 문)
이를 Defferred Execution(지연 평가)라 합니다
60. Q3. 식지 않는 떡밥 LINQ vs LOOP
LINQ가 빨라! LOOP가 빨라! 보다는...
LINQ가 다 같은 LINQ가 아니라는 걸 아는 게 중요!
streaming / buffering 방식으로 구문이 나뉜다
Streaming
Buffering
on Demand로 하나 씩 확인해 가며 평가
ex) FirstorDefault
일단 전부 다 확인해서 그 기록을 가지고 확인
ex) Max
62. reference
BOOK
Essential C# 5.0.pdf
CLI 관련
http://engineerportal.blogspot.kr/2012/07/introduction-to-c.html
메모리 구조
http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx
CLR Thread
http://blogs.msdn.com/b/yunjin/archive/2005/07/05/435726.aspx
LINQ 관련
http://hyunjong-lee.github.io/tech/2015/01/17/CSharp-Basic.html#linq
GC 관련
https://msdn.microsoft.com/en-us/magazine/bb985010.aspx
https://msdn.microsoft.com/ko-kr/magazine/cc163528.aspx
http://diehard98.tistory.com/135
http://stackoverflow.com/questions/2583644/difference-between-background-and-concurrent-garbage-collection
http://stackoverflow.com/questions/5223325/garbage-collection-and-finalizers-finer-points
https://msdn.microsoft.com/ko-kr/library/vstudio/0xy59wtx(v=vs.100).aspx
https://msdn.microsoft.com/ko-kr/library/ms973837.aspx
Thread Pool 관련
http://blogs.msdn.com/b/ericeil/archive/2008/06/20/windows-i-o-threads-vs-managed-i-o-threads.aspx
http://sysnet.pe.kr/100189072060
http://blog.naver.com/jjoommnn/130044743051
http://aviadezra.blogspot.kr/2009/06/net-clr-thread-pool-work.html
https://msdn.microsoft.com/en-us/magazine/dd419664.aspx
http://stackoverflow.com/questions/2099947/simple-description-of-worker-and-i-o-threads-in-net