델리게이트(delegate)는 C#에서 함수포인터와 비슷한 역활을 담당한다.


우선 함수포인터에 대해서 알아보자.


함수포인터는 함수의 주소값을 저장하는 역활을 한다.


1
2
3
4
5
6
7
8
int (*p)(int,int);
 
int add(int a, int b){
    return a+b;
}
= add;
p(3,2); // 5 리턴
 
cs


위와 같이 p가 함수포인터이다. 함수의 이름이 곧 함수의 주소값이기 때문에 p = add로 함수의 주소값을 함수포인터 p에 저장하였다.


함수 포인터와 같이 델리게이트(delegate)역시 함수를 대리호출 할 수 있다.


C#에서 함수포인터가 없고 델리게이트란 개념을 새로 만든 것은 포인터대신 참조자인 ref를 사용하는 것과 같은 이유이다.


주소값을 직접 저장하고 다루면 위험하기 때문이다.


사용자에게 주소값을 직접 다루지 않아도 포인터와 같은 역활을 하는 개념을 만든 것이다.


아래와 같은 형식으로 선언하면 된다.



delegate 반환형식 델리게이트이름 (매개변수 목록);


1
2
3
4
5
6
7
8
delegate int TestDele(int a,int b);
 
int add(int a, int b) {
    return a+b;
}
TestDele dele = new TestDele(add);
dele(3,2); //5 리턴
 

cs


델리게이트(delegate) 체인은 하나의 델리게이트 안에 여러개의 함수를 연결하여 연쇄적으로 호출하는 방식이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
delegate void testDele();
static void Main(string[] args)
{
            
    void print1()
    {
        Console.WriteLine("print1");
    }
    void print2()
    {
        Console.WriteLine("print2");
    }
    void print3()
    {
        Console.WriteLine("print3");
    }
    testDele dele = new testDele(print1);
    dele += new testDele(print2);
    dele += new testDele(print3);
    dele();
}
cs


- 출력 -

print1

print2

print3


위에서 보듯이 print1함수와 print2, print3 함수들을 델리게이트 testDele에 +=로 추가를 하고 dele()로 호출을 하니 넣은 순서대로 3개 함수가 모두 호출되는 것을 볼 수 있다.


Posted by 꿈만은공돌
,

C와 C++에서 직접 new 연산자와 malloc 함수를 이용해서 힙(heap)영역에 동적 메모리 할당을 받고 delete 연산자와 free 함수를 이용해서 동적 메모리를 해제하게 된다.


C, C++에서 메모리 할당과 해제 원리 : http://hijuworld.tistory.com/28


하지만 C#과 JAVA 에서는 가비지 컬렉터(garbage collecter)에 의해서 메모리 할당과 메모리 해제가 이루어진다.


사용하지 않는 메모리를 가비지 컬렉션(garbage collection)이 해제 시킨다.


우선 간단하게 메모리를 할당하는 방식에 대해서 알아 보자.




1. C#에서 객체 생성시 메모리 할당 방식

new 키워드를 통해 객체를 생성하게 되면 힙(Heap) 메모리 영역에 객체가 할당된다. C언어와 C++과 다른점은 메모리 첫영역부터 차례대로 할당하게 되고 할당이 가능한 부분의 첫 주소에 포인터로 가르키게 된다. 다음에 또 객체를 생성하면 할당 가능한 메모리의 포인터 영역부터 메모리를 할당하고 다시 해당 포인터는 할당된 사이즈 만큼 증가하게 됩니다.


C, C++과 다르게 이렇게 하면 메모리 할당이 가능한 영역을 찾는 과정이 없기 때문에 속도가 훨씬 빠르다.

아래 그림을 보면 쉽게 이해가 갈것이다.








2. C#에서 Garbage Collector에 의한 메모리 해제 방식

Test a = new TEST();

a = null;

위와 같은 코드를 만나면 처음에 할당한 변수 a가 가지고 있는 객체는 더이상 사용하지 않기 때문에 메모리 해제의 대상이 됩니다.

힙영역에 메모리가 계속 쌓이다 보면 특정 시점에서 Garbage collector에 의해 사용되지 않는 메모리(아래 그림에서 B, D)는 해제하게 된다.

Root Reference 메모리 영역에서 사용하는 메모리 영역을 관리하게 되고(아래 그림의 A와 C) 객체에서 할당한 객체도 존재(아래 그림에서 E)한다. Root Reference를 탐색하여 A와 C를 찾고 다시 A와 C를 검색하여 E를 찾아낸다.

그러면 그외에 메모리 영역인 B와 D는 사용하지 않는 메모리 영역으로보고 메모리를 해제한다.

그리고 남은 A, C, E를 다시 재배치 한다.

그리고 다음 객체를 할당할 메모리의 포인터의 위치도 재배치 한다.




여기까지가 간단하게 설명한 메모리 할당 및 해제 원리이다.

사실 가비지 컬렉션에 방식은 이외에도 상당히 복잡하다.


1. 세대별 가비지 컬렉션 방식 : http://hijuworld.tistory.com/41


2. 용량이 큰 객체에 메모리 할당 해제 방식 : http://hijuworld.tistory.com/46


3. 가비지 컬렉션의 모드에 따른 방식


따라서 이 3가지 방식에 대해서 다음 포스팅에서 설명하겠다.




참고 사이트 및 서적 

- c# GC.Collect() 정리 : http://helloit.tistory.com/40

- 유경상의 닷넷 블로그 : http://www.simpleisbest.net/post/2011/04/01/Review-NET-Garbage-Collection.aspx

- MSDN : https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals

- 뇌를 자극하는 C# 4.0(한빛미디어, 박상현 지음)





Posted by 꿈만은공돌
,




C#/닷넷에 자료형에는 소수를 저장하는 변수가 double과 decimal 두가지가 존재


double은 부동소수점 방식을 이용하고 


decimal은 고정소수점 방식을 이용


부동소수점 방식 장점으론 작은 메모리공간에 큰 소수를 저장 가능하나 정확성이 떨어진다.


고정소수점 방식은 연산 속도가 빠르고 수의 정확성이 높은데신 큰수를 저장할때 메모리를 많이 잡아먹게 된다. 


C#에서 double은 8byte 메모리를 사용하며 decimal은 16byte에 메모리를 사용한다.


- 부동소수점의 원리를 잘 설명한 블로그 : https://blog.naver.com/chdb57/221146120811


- 고정소수점의 원리를 잘 설명한 블로그 : https://chogahui05.blog.me/221246891984




- 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//부동소수점 double 사용
double double1 = 0.1;
double double2 = 1;
 
if (double1 + double2 == 1.1)
    Console.WriteLine("값 일치");
else
    Console.WriteLine("일치하지 않음");
   
 
//고정소수점 decimal 사용         
decimal decimal1 = 0.1M;
decimal decimal2 = 1.1M;
 
if (decimal1 + decimal2 == 1.1M)
    Console.WriteLine("값 일치");
else
    Console.WriteLine("일치하지 않음");



위의 예제처럼 부동 소수점은 == 연산을 사용해서 비교를 하면 안된다.


Posted by 꿈만은공돌
,