스택과 힙 메모리에 대한 설명은 여러 포스트들에서 다루었지만, 체계적으로 한번에 비교해서 설명이 되었다고 하기엔 조금 난잡한 포스트들이었다고 생각한다. 이번 포스팅에서는 C#의 관점에서 스택 메모리와 힙 메모리를 비교해보고 각각의 특성을 살펴보고자 한다.
c#의 경우 포인터가 직접적인 기능을 하지는 않지만 간접적으로 기능을 하고 있기에, c++보다는 이해하기 쉽지만, 그럼에도 불구하고 복사와 참조를 이해하기 위해서는 메모리 구조, 그리고 변수가 메모리에 어떻게 저장되는지 잘 이해하고 있어야 한다.
Stack 스택
1) stack은 임시메모리, 즉 잠시 사용하는 메모리이다. 메서드 호출 시 메서드의 지역 변수를 저장하는데 사용된다.
2) 이 메모리 영역은 LIFO(Last In First Out, 후입선출) 방식으로 관리된다. 즉, 마지막에 들어간 데이터가 가장 먼저 나온다.
3) 스택 메모리에 저장되는 데이터는 컴파일 시간에 미리 크기가 결정되어야 한다. 이는 값(value) 타입(int, float, struct...)의 데이터가 주로 스택에 저장된다는 것을 의미한다.
4) 메서드 실행이 완료되면 그 메서드의 지역 변수는 스택에서 자동으로 제거되어 메모리 관리가 간편하다.
ex) 함수 호출시 함수 안에 임시 변수를 선언하여 잠시 연산하고, 함수가 종료하면 날아가는 지역 변수들의 경우 stack.
Heap 힙
1) 힙 메모리는 동적으로 할당되는 메모리 영역으로, 주로 객체와 참조 타입의 데이터(ex: 클래스의 인스턴스)가 저장된다.
2) 힙 메모리에 저장된 데이터의 생명 주기는 가비지 컬렉터(Garbage Collector)에 의해 관리된다. 이는 참조되지 않은 객체를 자동으로 감지하고 메모리에서 제거한다.(C++에서처럼 직접 관리해줄 필요가 없다)
3) 힙은 스택에 비해 메모리 관리가 복잡하고, 가비지 컬렉션이 실행될 때 성능 저하가 발생할 수 있다.
4) 힙에 저장된 객체는 참조에 의해 접근되며, 두 변수가 동일한 객체를 참조할 수 있다.
복사와 참조 - 값 타입과 참조 타입
값 타입(Value Type)
값 타입의 변수를 다른 변수에 할당하면 값이 복사된다. 즉, 변수에 저장된 데이터의 실제 값이 복사된다. 따라서, 하나의 변수를 변경해도 다른 변수에 영향을 미치지 않는다. 값 타입의 예로는 기본 데이터 타입(int,float 등)과 구조체(struct)가 있다.
struct Point
{
public int X;
public int Y;
}
public class ValueTypeExample
{
public static void Main()
{
Point p1 = new Point();
p1.X = 10;
p1.Y = 20;
// p2는 p1의 복사본입니다. 즉, X와 Y의 값이 복사됩니다.
Point p2 = p1;
p2.X = 30; // p2의 X 값을 변경합니다.
Console.WriteLine($"p1: X={p1.X}, Y={p1.Y}"); // p1: X=10, Y=20
Console.WriteLine($"p2: X={p2.X}, Y={p2.Y}"); // p2: X=30, Y=20
}
}
이 예시에서 'Point'는 struct를 사용하여 정의한 값 타입이다. 'p2 = p1'을 수행하면 'p1'의 값(X와Y값)이 'p2'에 복사된다. 따라서, 'p2'의 X값을 변경해도 'p1'에는 영향을 주지 않는다.
찹조 타입(Reference Type)
참조 타입의 변수를 다른 변수에 할당하면 메모리 주소(참조)가 복사된다. 이 경우, 두 변수는 동일한 객체를 참조하게 되며, 객체의 상태 변경이 두 변수에 모두 반영된다. 클래스(class)가 참조 타입의 대표적인 예이다.
class PointRef
{
public int X;
public int Y;
}
public class ReferenceTypeExample
{
public static void Main()
{
PointRef p1 = new PointRef();
p1.X = 10;
p1.Y = 20;
// p2는 p1의 참조입니다. 즉, p2와 p1은 동일한 객체를 가리킵니다.
PointRef p2 = p1;
p2.X = 30; // p2의 X 값을 변경하면 p1의 X 값도 변경됩니다.
Console.WriteLine($"p1: X={p1.X}, Y={p1.Y}"); // p1: X=30, Y=20
Console.WriteLine($"p2: X={p2.X}, Y={p2.Y}"); // p2: X=30, Y=20
}
}
이 예시에서 'PointRef'는 class를 사용하여 정의한 참조 타입이다. 'p2 = p1'을 수행하면 'p1'이 가리키는 객체의 참조(메모리 주소)가 'p2'에 복사된다. 따라서, 'p2'를 통해 객체의 X 값을 변경하면, 'p1'을 통해서도 변경된 값을 볼 수 있다. 이는 'p1'과 'p2'가 메모리 상에서 동일한 객체를 가리키기 때문이다.
값 타입과 참조 타입의 선택은 프로그램의 성능과 메모리 사용 방식에 큰 영향을 미칠 수 있기 때문에, 이 차이를 이해하고 값 타입과 참조 타입을 잘 선택하여 코드를 짜야 한다.
그동안의 포스트들도 참고해 주시면 더더욱 이해가 쉬울 것입니다.
https://nybot-house.tistory.com/36
1. 메모리 속 변수들에 대한 설명 - Stack 스택
Stack Variables 스택 변수 : 변수가 많아질수록 메모리 공간이 위로 쌓여간다고 하여 stack. 컴퓨터가 변수를 인식/접근하는 방법 : 메모리 맵에서 가장 위에서부터 몇 번째에 위치하고 있는지로 구분
nybot-house.tistory.com
https://nybot-house.tistory.com/39
4. 스택 메모리 - 스택 프레임 Stack Frame, Call Stack, this
스택 메모리는 흔히 생각하듯이 변수a 변수b 이런 식으로 쌓여가면서 동작하지 않는다. 실제로 스택 메모리는 변수별로 쌓여가는 것이 아니라 Stack Frame 단위로 메모리를 쌓아가면서 동작한다.
nybot-house.tistory.com
https://nybot-house.tistory.com/41
6. 힙 메모리 Heap Memory 에 대한 모든 것 (2) - 예제 + Memory Leak 메모리 릭 방지
힙 메모리 사용 방법 1) C Style 2) C++ Style 3) Safer C++ Style 1. C스타일 (1)malloc 명령어 사용 (2) C style class Cat 컴파일: 된다. 그런데, 분명히 컨스트럭터와 디스트럭터를 생성해 놓았음에도 불구하고 "meow
nybot-house.tistory.com
https://nybot-house.tistory.com/42
7. 힙 스택 스태틱 Heap Stack Static - 언제 어떻게 사용해야 할까
프로세스 메모리 구조는 이런 식으로, 스택과 같은 경우는 위쪽에서부터 촘촘하게 아랫방향으로 진행되고, 힙은 아래쪽에서 위 방향으로 채워져 올라가는데 힙 메모리의 특성상 중간중간에 비
nybot-house.tistory.com
'C# 기초 프로그래밍 > C# Basic' 카테고리의 다른 글
[C# Basics] 재귀 함수 (0) | 2024.06.11 |
---|---|
[C# Basics] 다형성 (polymorphism) - OOP의 핵심 개념 (0) | 2024.04.15 |
[C# Basics] 캡슐화 / 은닉성 - OOP 의 핵심 개념(객체 지향 프로그래밍) (0) | 2024.04.12 |
[C# Basics] 객체지향 OOP란 무엇인가? - 핵심 4개념과 개론 (0) | 2024.04.12 |
[C# Basics] 생성자 Constructor (0) | 2024.04.02 |
<C# Basics> 복사와 참조 (struct, class의 차이, 깊은 복사) (0) | 2023.12.23 |
<C# Basics> ref, out 키워드 (0) | 2023.12.11 |
<C# Basics> 함수/메서드 (2) | 2023.12.11 |