C#에서는 데이터를 메모리에 저장하는 방식이 두가지로 나뉜다.
값 형식과 참조 형식이다.
값 형식은 데이터를 저장할 때 스택(stack) 메모리에 저장하고
참조 형식은 데이터를 저장할 때 힙(heap) 메모리에 저장한다.
값 형식 예시
값 형식의 자료형 중 하나인 int 변수 num을 생성하고 6을 할당한다.
int 변수 num2을 생성하고 num2에 num을 할당한다.
마지막으로 num2에 10을 추가로 할당하고 num1, num2을 출력했다.
num2값만 바꿨으니 예상대로 6이 출력이 된다.
참조 형식 예시
int 변수 대신 참조 형식의 자료형 중 하나인 array(배열) 변수를 사용하여 위와 똑같이 코드를 구성하고 실행해보았다.
위의 값 형식과 똑같이 코드를 구성하고 실행했는데 결과가 다르다.
array2의 값만 바꿨는데 array의 값도 같이 바뀌었다.
값 형식과 참조 형식의 데이터 저장 방식 (스택/힙)
- 값 형식의 저장 방식
위에서 작성했던 예시를 가져와 데이터 저장 방식을 설명하자면,
1). 변수 num에 6을 할당시키는 코드
int num을 생성하고 6을 할당시켰을 때, 스택에 새로운 메모리 공간 (주소1)이 생성되고
그 안에 6이라는 값이 저장된다.
num 변수가 6이라는 값을 가리킨다.
2). 변수 num2에 num을 할당시키는 코드
스택에 새로운 메모리 공간 (주소2)이 새로 생성되고, 그곳 안에 6이라는 값이 그대로 복사되어 저장된다.
3). 변수 num2에 100을 재할당시키는 코드
앞서 새로 생성한 주소2 안의 값이 6 -> 100으로 바뀐다.
따라서 결과값이 num은 6, num2은 100이 되는것이다.
- 참조 형식의 데이터 저장 방식
참조 형식도 위 코드 예시에 빗대어 설명
1). { 1, 2 } 값을 가지고 있는 배열 array를 생성하는 코드
array 변수로 생성한 데이터 { 1, 2 } 가 새로 생성된 힙 메모리 공간(주소1)에 저장이 된다.
그리고 그 주소명(주소1) 자체가 새로 생성된 스택 메모리 공간(주소1에) 저장이된다.
2). array2에 array를 할당시키는 코드
array2에 array를 할당시켰을 때, 데이터 자체는 { 1, 2 }로 array2와 array가 다르지 않으므로 힙에 추가로 생성되진 않는다.
스택에서 새로운 메모리 공간 (주소3)을 생성하고 이 또한 주소2처럼 힙 메모리의 주소1을 저장한다.
3). array2의 첫번째 값을 3으로 바꾸는 코드
array2의 첫번째 값을 3으로 바꾸면 힙 메모리 공간에 있던 값도 3으로 바뀐다.
결과적으로, 스택에 서로 다른 메모리 공간이 생성되어도(array와 array2), 저장된 내용물이(또는 가리키는 주소가)
힙 메모리에 있는 주소1로 같으므로 array와 array2는 같이 움직이게 되는 것이다.
값 형식인 데이터 타입 & 참조 형식인 데이터 타입
값 형식 데이터 타입
byte | short | int | long | float | double |
decimal | char | bool | struct | enum |
참조 형식 데이터 타입
class | array(배열) | string | object |
예외 : string
string 타입은 참조 형식이지만, 동시에 불변(Immutable)형식이기도 하다.
만약 string 변수 msg에 "hi"를 할당하고, msg2에 msg를 할당하는 상황이라 하였을 때,
다른 참조 방식과 별다를 것 없이 똑같이 진행된다.
하지만 msg2의 값을 Hello로 변경시켰을 때, 참조 방식처럼 힙 메모리에 있는 주소h1의 "hi" 가 "Hello"로 바뀌는 것이 아닌
힙에 추가로 새로운 메모리 공간(주소h2)을 생성한다.
그리고 스택의 msg2는 주소h1을 가리키는 것이 아닌, 새로운 주소h2를 가리키게 된다.
string은 불변 객체이므로 주소h1 메모리 공간에서 값만 바꿀수가 없고, 새로운 메모리 공간을 생성해야 한다.
따라서 string은 참조 형식이지만, 결과값은 값 형식 처럼 나오게 된다.
'C# 기초' 카테고리의 다른 글
[C#] Collections (0) | 2023.10.24 |
---|---|
[C#] ref, in, out 참조에 의한 호출 (0) | 2023.10.23 |
[C#] 일반화 프로그래밍 (제네릭/Generic) (1) | 2023.10.20 |
[C#] 모노 싱글톤 (0) | 2023.10.19 |
[C#] get set 프로퍼티 (1) | 2023.10.10 |