본문 바로가기

프로그래밍/기본기ㆍ자료구조

C# GC의 이해 및 메모리 최적화

728x90
반응형

 
# GC (가비지 컬렉터 - Garbage Collector)
가비지 컬렉터는 Java나 C#에서 메모리를 자동으로 해제해주는 기능이다.(이하 GC)
 
C#은 C/C++의 메모리 할당보다 빠르다. C/C++처럼 자유 메모리 블록을 검사할 필요가 없으며 단순히 포인터 값을 증가 시키는 것이 전부이기 때문이다.
 
C#의 메모리 할당 방식은 메모리 조각이 발생하지 않는 방식이다.
(불변 객체인 String 같이 작은 크기의 객체들이 힙 상에 아주 많이 존재하기 때문에 이러한 형태의 방식으로 만들어졌다)
 
GC는 특정 조건을 만족하는 상황이 되면 현재 쓰레드들을 모두 중단시키고 GC 쓰레드를 실행시킨다.
(GC쓰레드는 평소에 아무것도 안하고 잠들어 있다)
 
GC는 세대별로 구분을 할 수가 있는데 힙 상의 객체를 객체의 생존 시간에 따라 0,1,2세대로 구분한다.
0세대는 최근에 생성된 객체
1세대는 1회의 GC동안 살아남은 객체
2세대는 2회 이상의 GC동안 살아남은 객체
 
기본적으로 GC는 0세대에 대해서만 집중적으로 처리한다.
즉, 기본적으로는 1세대 2세대는 GC를 수행하지 않는다는 것이다.
 
GC는 0세대가 사용할 수 있는 메모리가 줄어들어 특정 한계점에 도달하게 되면
GC 1세대 Collect를 수행하게 되는데 이 때 0세대, 1세대를 처리하며
0세대에서 살아남은 객체는 1세대로, 1세대에서 살아남은 객체는 2세대로 분류된다.
 
보통 게임개발을 하다보면 로비에서 인게임으로 진입하거나, 인게임에서 로비로 되돌아올 때
강제로 GC.Collect()를 호출하는 사람들이 종종 있는데 이는 좋지 못한 방법이다.
GC.Collect()를 호출하게되면 0,1,2세대를 전부 돌면서 처리하게 되는데
이 때 살아남은 객체들은 각각 한 세대식 단계업을 하게 되버린다.
 
GC 2세대는 GC 1세대 Collect를 하게 되어도 GC 0세대의 메모리 공간에 여유가 없을 것 같은 상황에
GC 2세대 Collect를 수행시킨다.
 
그리고 클래스의 정적 필드(Static)으로 기록된 객체들은 명시적으로 해당 객체를 null로 할당해주어야 한다.
그렇지 않는 한 절대 해제되지 않는다.
 
최적화 관련해서는 사실 별거 없다.
1. String을 사용할 때 +연산자는 되도록 사용하지 말자
- String은 불변객체이기 때문에 +연산자를 하면 내부적으로 새로운 객체가 생성되고
기존 객체는 참조 없이 쌓이기만 한다. 변화가 자주 일어나는 경우 String 대신에 StringBuilder를 사용하자
 
2. 웬만하면 박싱/언박싱이 일어나지 않도록 하자
- 값 타입에서 참조 타입으로, 참조 타입에서 값 타입으로 변환하는 작업은 굉장히 느리고 좋지 못한 방법이다.
값 타입이 참조 타입으로 변환될 때 힙 메모리에 쌓이고 값이 복사된다.
 
3. 자원을 다룰 때 using 키워들 이용하자
- using 키워드를 이용하면 괄호( {} )를 빠져나올 때 자동으로 Dispose를 해준다.
여기서 자원이란 파일, 폰트 등과 같은 Resource를 말한다.
 
4. C#에서 System.Collections.Generic.List를 쓸 필요 없는때에는 쓰지마라
- List의 내부 구조를 열어보면 Linked List처처럼 만들어 놓은 List가 아니라 ArrayList처럼 만들어놨다.
즉, 편하게 Add, Remove를 하지만 내부적으로는 새로운 배열에 복사해주는 형식이다.
 
5. 단일 원칙을 지켜라
- 객체지향에서 단일 원칙을 지켜야하는것은 너무나도 당연하지만 그렇지 않고 사용하는 사람들이 많다.
간단하게 말하자면 하나의 CS파일에 하나의 Class만을 사용하고, 하나의 Class에는 Class 이름에 맞는
단일 책임을 갖는 구조를 구현해야한다는 것이다.
'연필'이라는 Class가 있으면 그 Class는 딱 '연필'에 대해서만 구현해야한다.
단일 원칙만 지켜줘도 내가 모르는 곳에서 참조가 끊어지지 않고 메모리에 계속 남아돌게 되는 상황을 최대한 피할 수 있다.
 
6. string 대소문자 구분 없이 비교할 때 Compare 함수를 사용해라
- 흔히들 대소문자 구분 없이 비교하기 위해 ToUpper()나 ToLower()를 사용하곤 한다.
string은 불변 객체이기 때문에 ToUpper()나 ToLower()를 사용하면 내부적으로 불필요한 객체 2개를 만들게 되고
이는 곧 GC의 대상이 된다.
string.Compare(string, string, bool) 함수를 사용하면 불필요한 객체를 만들지 않고 비교가 가능하다.
파라미터는 (비교1, 비교2, 대소문자구분(true : 구분 안함, false : 구분함))이다

다람쥐와 포동포동이

 
 
 
 

 

RememberCook 9월 28일 정식 출시!

두번째 게임인 RememberCook이 출시되었습니다. 귀여운 캐릭터들이 나오는 간단한 게임이며 플레이어의 공간인지능력을 테스트하는 게임입니다. 아래 링크를 통해 다운 받으실 수 있으니 많은 관

chipmunk-plump-plump.tistory.com

반응형

'프로그래밍 > 기본기ㆍ자료구조' 카테고리의 다른 글

C, C++, C# 언어의 차이점  (2) 2021.02.02
Dictionary와 HashTable의 차이  (0) 2021.02.01
String, StringBuilder의 차이  (4) 2021.01.30
Boxing UnBoxing (박싱 언박싱)  (2) 2021.01.29
OSI 7계층  (0) 2021.01.28