일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- HDRP
- 버텍스 쉐이더
- TCP
- Heap
- 프로세스
- 정렬
- SQL
- 자료구조
- 코스닥
- 운영체제
- unity
- 배칭
- 멀티스레드
- 주식
- SRP
- 통신
- 쉐이더
- 코스피
- 픽셀 쉐이더
- vertex shader
- URP
- 네트워크
- SQLD
- 디자인패턴
- 유니티
- 유니티 최적화
- 렌더링파이프라인
- SQL시험
- c#
- 스레드
- Today
- Total
Let's Girin!
[C#] 값 형식과 참조 형식/ 얕은 복사와 깊은 복사 본문
1. 값 형식과 참조 형식
값 형식(Value Types) : 변수가 값을 담는 데이터 형식, 스택 메모리 영역
참조 형식(Reference Types) : 변수가 값 대신 값이 있는 곳의 위치(참조)를 담는 데이터 형식, 힙 메모리 영역
2. 스택(Stack)과 값 형식
{
int a = 100;
int b = 200;
int c = 300;
}
이 코드에 선언된 세 변수 a, b, c는 차례대로 스택에 쌓였다가 코드 블록이 끝나면서 스택에서 걷혀 제거된다.
c : 300 |
b : 200 |
a : 100 |
▷ 값 형식의 변수는 모두 이 스택에 저장된다. 코드 블록 안에서 생성된 모든 값 형식의 변수들은 프로그램 실행이 중괄호 "}"를 만나면 메모리에서 제거된다. 즉, 스택에 쌓인 데이터들은 코드 블록이 사라지는 시점에 함께 제거된다.
3. 힙(Heap)과 참조 형식
▷ 힙은 저장된 데이터를 스스로 제거하지 못한다. 가비지 컬렉터(Garbage Collector)가 필요하다.
* 가비지 컬렉터(GC)
☞ 프로그램 뒤에 숨어 동작하면서 힙에 더이상 사용하지 않는 객체가 있으면 그 객체를 쓰레기로 간주하고 수거하는 기능을 한다!
▷ 코드 블록이 끝나는 시점과 상관없이 데이터를 유지하고 싶을 때 힙 메모리 영역을 사용한다.
▷ 참조 형식의 변수는 힙과 스택을 함께 이용하는데 힙 영역에는 데이터를 저장하고,
스택 영역에는 데이터가 저장된 힙 메모리의 주소를 저장한다.
▷ 데이터를 직접 저장하는 대신 실제 데이터가 저장된 메모리의 주소를 "참조"한다고 해서 "참조 형식"인 것이다!
{
object a = 10;
object b = 20;
}
이 코드를 실행하면 실제 값 10, 20은 힙에 저장하고, a와 b는 값이 저장된 힙의 주소만 스택에 저장해둔다.
b : &2000 |
a : &4000 |
[Stack]
20 (메모리 주소: 2000) |
10 (메모리 주소: 4000) |
[Heap]
코드 블록이 끝나는 지점에서 a와 b는 스택에서 사라지지만 힙에는 여전히 10과 20이 남게된다. 이 데이터들은 GC가 수거해 간다.
4. 값 형식과 참조 형식 차이!
▷ 스택은 변수의 생명 주기가 다하면 자동으로 데이터를 제거하는 메모리 영역이다.
▷ 힙은 더이상 데이터를 참조하는 곳이 없을 때 가비지 컬렉터(GC)가 데이터를 치워주는 구조의 메모리 영역이다.
5. 얕은 복사
//클래스 선언
class MyClass
{
public int MyField1;
public int MyField2;
}
{
MyClass source = new MyClass();
source.MyField1 = 10;
source.MyField2 = 20;
MyClass target = source;
target.MyField2 = 30;
Console.WriteLine("{0} {1}", source.MyField1, source.MyField2);
Console.WriteLine("{1} {1}", target.MyField1, target.MyField2);
}
▷ 클래스는 참조 형식이다.
① source 객체를 할당한다.
source |
MyField1 = 10 MyField2 = 20 |
② source를 복사해서 받은 target은 힙에 있는 실제 객체가 아닌 스택에 있는 참조를 복사해서 받는다.
source |
target |
MyField1 = 10 MyField2 = 20 |
③ source와 target이 같은 메모리를 바라보게 된다.
④ 따라서 위의 코드는 target의 MyField2를 30으로 바꿨는데 source의 MyField2도 30으로 바뀌게 된다.
결과값은
10 30
10 30
⑤ 이렇게 객체를 복사할 때 참조만 살짝 복사하는 것을 얕은 복사(Shallow Copy)라고 한다.
6. 깊은 복사
class MyClass
{
public int MyField1;
public int MyField2;
public MyClass DeepCopy()
{
MyClass newCopy = new MyClass();
newCopy.MyField1 = this.MyField1;
newCopy.MyField2 = this.MyField2;
return newCopy;
}
}
① 객체를 힙에 새로 할당해서 그곳에 자신의 멤버를 일일이 복사해 넣는다.
② 힙에 보관되어 있는 내용을 객체로부터 복사해서 받아 별도의 힙 공간에 객체를 보관하는 것이 깊은 복사(Deep Copy)이다.
7. 얕은 복사 VS 깊은 복사 예제
using System;
namespace DeepCopy
{
class MyClass
{
public int MyField1;
public int MyField2;
public MyClass DeepCopy()
{
MyClass newCopy = new MyClass();
newCopy.MyField1 = this.MyField1;
newCopy.MyField2 = this.MyField2;
return newCopy;
}
}
class MainApp
{
static void Main(string[] args)
{
Console.WriteLine("Shallow Copy");
{
MyClass source = new MyClass();
source.MyField1 = 10;
source.MyField2 = 20;
MyClass target = source;
target.MyField2 = 30;
Console.WriteLine($"{source.MyField1} {source.MyField2}");
Console.WriteLine($"{target.MyField1} {target.MyField2}");
}
Console.WriteLine("Deep Copy");
{
MyClass source = new MyClass();
source.MyField1 = 10;
source.MyField2 = 20;
MyClass target = source.DeepCopy();
target.MyField2 = 30;
Console.WriteLine($"{source.MyField1} {source.MyField2}");
Console.WriteLine($"{target.MyField1} {target.MyField2}");
}
}
}
}
▷ 결과값
Shallow Copy
10 30
10 30
Deep Copy
10 20
10 30
'C#' 카테고리의 다른 글
[C#] is 키워드 (0) | 2024.04.18 |
---|---|
[C#] 클로저(Closure) (0) | 2023.09.21 |
[C#] 구조체와 클래스의 차이 (2) | 2022.09.14 |