TIL(Today I Learned)

C# 메모리의 작동 방식(구조체와 클래스의 차이) - TIL#29

Najdorf 2024. 2. 1. 20:51
728x90

C# 메모리
하드 디스크 : 컴퓨터에 물리적으로 파일을 저장
메모리 : 프로그램이 실행되는데 필요한 데이터가를 저장

메모리의 종류
Code, Data, Heap, Stack
1. 프로그래머가 작성한 코드를 보관
2. static, const, 전역변수 : 어플리케이션 전반에 필요한 데이터 저장
3. 참조 데이터 (객체) 저장
4. 로컬 변수, 매개 변수 저장 : 어플리케이션 실행 순서에 필요한 데이터 보관

int x = 10; 라고 한다면
예를 들어, 메모리 주소가 00000000인 메모리에 10을 저장하고 이름을 x로 한다

변수명 같은 경우는 Stack에 저장, 참조 데이터의 경우 Heap에 저장
따라서, Person chad = new Person(age:32, name:"chad"); 라고 한다면
chad는 스택에 저장되고 '32, chad'가 저장된 메모리 값의 주소를 값으로 저장한다

스택에 저장된 값들은 쌓여서 넘치게 되면 StackOverFlow가 발생해 프로그램이 정상적으로 작동하지 않는다.
따라서 메모리 관리를 위해서는 삭제도 고려해야 함

그럼 값은 언제 삭제되는 걸까?
예를 들어 int x = 10; 같은 것
정답은 블레이스(중괄호)가 끝날 때이다.
그럼 블레이스가 끝나도 값을 사용하고 싶으면?
그래서 그런 값들을 객체로 만들어서 힙에 저장하는 것이다.

다음 코드의 문제점?
void Update()
{
Monster orc = new Monster();
Debug.Log("");
}
1. 스택에 orc라는 이름을 할당하고 Heap에 새로운 Monster() 형 값을 생성
2. 블레이스가 끝나고 스택의 orc 변수를 제거
3. 다시 1번으로 가서 orc라는 이름의 변수를 만들고 또 다른 Monster 형 값을 생성한뒤 메모리 값을 할당
4. 처음에 Heap에 만든 Monster 형 값은 쓰레기 값이 되어버림
5. 반복

C#에는 가비지 컬렉터라고 저런 연결없는 값들을 수거해가는 것이 있음
근데 언제 작동될지는 모름, 결국 우리는 쓰레기 값을 다루지 못하고 그만큼 메모리 낭비가 생김

Managed 언어는 이런 방식으로 관리를 해주는 언어인데
대표적인게,
Managed 언어 - C#
Unmanaged 언어 - C++
같은 것이 있다. C++은 그래서 저렇게 가비지가 쌓이면 C#과는 다르게 언젠가 Heap이 터짐

위의 코드는 이해하기 쉬운 편이라 저렇게 코드를 작성하지 않을 수 있는데,
아래 코드와 같은 경우는 다음과 같이 실수할 수도 있다.

IEnumerator CheckTimer()
{
return yield new WaitForSecond(5);
}

그럼 new Vector3를 지속적으로 하는 경우는?
정답은 위와 같은 현상이 생기지 않는다.
이유는 Vector3는 클래스(참조형)가 아닌 구조체(값형) 이기 때문이다.

클래스 선언 안에 다음과 같이 문자열을 정의를 한다면?
str = "유저 이름";
str += "name";

이렇게 되면 메모리에는 str += name; 을 하게 될 때
원래 만들었던 "유저 이름" 메모리 뒤에 추가하지 않고
따로 "유저 이름 name" 이라는 새로운 값을 만들어 할당한다.
이와 같은 현상을 메모리 파편이라고 한다.
메모리는 길이의 불변성이 있다.

이를 해결하기 위해선 
1. string을 한번에 제작하면 된다. (보간 문자열, 스트링 포맷, + 연산자)
2. StringBuilder 의 사용

그럼 StringBuilder는 어떤 식으로 작동하나?
그냥 문자가 들어갈 여유 공간까지 생각해서 메모리를 할당한다!
넘어가면 그 때는 일반 문자열과 같이 새로 만든다.

스택에 할당된다면 '값 형식' (call by Value)
힙에 할당된다면 '참조 형식' (call by Reference)

값 형식의 대표적인 것은
C# 기본 타입(int, float, bool, char, ...), 구조체, enum 등

참조 형식은
string, class, 배열, interface, delegate 등

만약 면접에서 구조체와 클래스의 차이를 물어본다면
대부분은 메모리 구조에 대한 이해를 알고 있는 지 물어보는 것이다.

static 사용하는 경우 Stack이 아닌 Data에 저장됨
Data에 저장된 것은 프로그램 시작 시 생성, 종료 시 삭제된다.
그래서 싱글톤 선언을 하면 다른 곳에서도 계속 쓸 수 있음

728x90