세그먼트(Segment)
- 코드 세그먼트 : 컴파일된 프로그램이 저장되는 영역, 일반적으로 read-only 속성이다.
- 데이터 세그먼트 : 전역 변수 및 정적 변수가 저장되는 영역
- 힙 세그먼트 : 동적으로 할당된 변수가 할당되는 영역
- 스택 세그먼트 : 함수 매개 변수, 지역 변수 및 기타 함수 관련 정보가 저장되는 영역.
힙 세그먼트(Heap segment)
힙 세그먼트는 동적 메모리 할당에 사용되는 메모리를 적재한다. C++에서 new 연산자를 사용해서 메모리를 할당하면 이 메모리는 응용 프로그램의 힙 세그먼트에 할당된다.
int main()
{
int* ptr = new int;//ptr은 힙에서 4바이트로 할당됨.
int* array = new int[10];//array는 힙에서 40바이트로 할당됨.
//차례로 선언했지만 순차적 메모리 주소를 갖는 것은 아님
int* ptr1 = new int;
int* ptr2 = new int;
}
힙의 장단점
- 힙에 메모리를 할당하는 것은 비교적 느리다.
- 할당된 메모리는 명시적으로 할당 해제하거나 (delete) 응용 프로그램이 종료될 때까지 유지된다.(메모리 릭 주의
- 동적으로 할당된 메모리는 포인터를 통해 접근한다: 포인터를 역참조하는 것은 변수에 직접 접근하는 것보다 느리다.
- 힙은 큰 메모리 풀이므로 큰 배열, 구조체 또는 클래스를 할당할 수 있다.
스택 세그먼트
- 스택 세그먼트(=콜스택)는 메인() 함수부터 현재 실행 지점까지의 모든 활성 함수를 추적하고 모든 함수 매개 변수와 지역 변수의 할당을 처리한다.
- 스택은 후입선출(LIFO) 자료구조이다. 즉, 함수 호출이 끝나고, 이전 함수로 돌아갈 때 이 함수의 바로 이전함수로 돌아가야한다. 그래서 컴퓨터는 내부적으로 스택 세그먼트를 스택 자료구조로 구현한다.(재귀)
- 콜 스택(call stack) 이란 컴퓨터 프로그램에서 현재 실행 중인 서브루틴(함수)에 관한 정보를 저장하는 스택 자료구조이다.
- 응용 프로그램이 시작되면 메민() 함수가 운영체제에 의해 호출 스택에 푸시됨.
- 프로그램 실행
- 함수호출이 발생하면 함수가 콜 스택에 푸시됨.
- 현재 함수가 끝나면 해당함수는 콜 스택에서 해제 됨.
- 따라서 콜 스택에 푸시된 함수를 살펴보면 현재 실행 지점에서 이동하기 위해 호출된 모든 함수를 볼 수 있다.
#include <iostream>
using namespace std;
void func()
{
cout << "func" << endl;
}
void func2()
{
cout << "func" << endl;
}
void func3()
{
cout << "func" << endl;
}
int main()
{
int* ptr = new int;//ptr은 힙에서 4바이트로 할당됨.
int* array = new int[10];//array는 힙에서 40바이트로 할당됨.
//차례로 선언했지만 순차적 메모리 주소를 갖는 것은 아님
int* ptr1 = new int;
int* ptr2 = new int;
//콜 스택 ex
func();
func2();
func3();
}
- 콜 스택 자체는 고정된 크기의 메모리 영역이다.
- 스택 프레임(stack frame) : 콜 스택에 넣고 빼는 데이터, 하나의 함수 호출과 관련된 모든 데이터를 추적
- 스택 포인터(stack pointer) : cpu의 작은 조각인 레지스터는 현재 호출 스택의 최상위 위치를 가리킨다.
콜 스택 발생 순서
- 프로그램에 함수 호출이 발생
- 스택 프레임이 생성되고 콜 스택에 푸시된다. 스택 프레임은 다음과 같이 구성된다.
- 함수가 종료되면 복귀할 주소
- 함수의 모든 매개변수
- 지역 변수
- 함수가 반환할 때 복원해야 하는 수정된 레지스터의 복사본
- CPU가 함수의 시작점을 점프한다.
- 함수 내부의 명령어를 실행한다.
함수가 종료 되면 다음단계가 수행된다.
- 레지스터가 콜 스택에서 복원된다.
- 스택 프레임이 콜 스텍에서 튀어나온다. 이렇게 하면 모든 지역 변수와 매개 변수에 대한 메모리가 해제된다.
- 반환 값이 처리된다.
- CPU는 반환 주소에서 실행을 재개한다.
일반적으로 콜 스택이 어떻게 동작하는지에 대한 모든 세부사항은 중요하지 않다. 그러나 함수가 호출될 때와 종료될 때 함수가 콜 스택에서 효과적으로 작동하다는 것을 이해하면 재귀를 이해할 때와 디버깅할 때 유용하다.
스택 오버플로 (stack overflow)
- 스택 세그먼트는 크기가 제한되어 있으므로 제한된 양의 데이터만 저장할 수 있다.
- window 운영체제에서 기본 스택 세그먼트의 크기는 1MB다.
- 응용 프로그램이 스택 세그먼트에 너무 많은 정보를 담으려고 하면 스택 오버플로(stack overflow)가 발생한다.
- 스택 오버플로는 보통 스택 세그먼트에 1)너무 많은 변수 2)중첩된 함수 호출 이다.
ex)1) 너무 큰 배열 2)무한 루프
void foo()
{
foo(); //2) 무한 루프
}
int main()
{
int stack[100000000]; //1) 너무 많은 크기의 배열
foo();
}
- 스택에 메모리를 할당하는 것은 비교적 빠르다.
- 스택에 할당된 메모리는 스택 범위에 있을 때만 접근 할 수 있다.
- 스택에 할당된 모든 메모리는 컴파일 타임에 알려진다. 메모리는 변수를 통해 직접 접근 가능.
- 스택은 비교적 크기가 작으므로 스택 공간을 많이 차지하는 지역 변수를 만드는 것은 좋지 않다.
출처: https://boycoding.tistory.com/235 [소년코딩]
'C++' 카테고리의 다른 글
Visual Studio 2015 - 자주 사용하는 단축키 (0) | 2020.08.19 |
---|---|
[C++] 포인터(Pointer) (0) | 2020.07.23 |
[C++] 메모리누수 체크 (0) | 2020.07.23 |
[C++] char[] 와 char*의 차이 (0) | 2020.07.22 |
[C++] 포인터(Pointer)와 레퍼런스(Reference : 참조자)의 차이 (0) | 2020.07.22 |