[내일배움캠프 Day10] 메모리 관리

2024. 12. 31. 17:22·내일배움캠프/TIL

1.메모리 영역

C++ 환경은 메모리를 효율적으로 관리하기 위해서 메모리를 여러 영역으로 나눕니다

 

2.코드 메모리

코드 메모리(code memory)는 프로그램 코드를 보유하는 영역입니다. 프로그램이 실행될 때 C++ 실행 환경은 코드 메모리 위에 있는 문장을 하나하나 실행합니다. 코드 메모리는 프로그램이 종료될 때 해제됩니다.

 

3.정적 메모리

정적 메모리(static memory)는 전역 객체(global object)(전역 객체는 어떤 함수에도 속하지 않는 함수 외부에 있는 객체)**와 정적 객체(static object)**를 보유하는 영역입니다. 프로그램이 종료되면 모든 객체들을 정리하고 메모리 위에서 해제합니다.

/**************************************************************
 * 프로그램이 존재하는                                        *
 * 동안 계속해서 메모리에 존재하는                            *
 * 전역 변수, 정적 변수를 사용하는 프로그램                   *
 **************************************************************/
#include <iostream>
using namespace std;

int first = 20;  // 정적 메모리 위에 올라가는 전역 변수
static int second = 30 ;  // 정적 메모리 위에 올라가는 전역 정적 변수

int main()
{
  static int third = 50;   // 정적 메모리 위에 올라가는 정적 변수

  cout << "전역 변수의 값: " << first << endl; // 20
  cout << "전역 정적 변수의 값: " << second << endl; // 30
  cout << "지역 정적 변수의 값: " << third; // 50
  return 0;
}

 

4.스택 메모리

스택 메모리(stack memory)는 함수의 지역 변수와 매개변수를 보유합니다.

스택이란 후입선출(last-in-first-out) 컨테이너로 마지막에 넣은 것이 가장 먼저 꺼내지는 자료 구조입니다. 스택의 이러한 특성은 함수의 지역 변수와 매개변수를 저장하는 데 적합합니다. 함수를 호출하면 시스템은 지역 변수와 매개변수를 스택 메모리에 삽입(push)합니다. 그리고 함수가 종료하면 이러한 것들을 삭제(pop)해서 버립니다.

 

장점

객체는 함수 스코프 내부에 있을 때만 스택 메모리에 유지되며, 함수의 스코프를 벗어나면 삭제되어서 더 이상 접근할 수 없게 됩니다.

 

제한

  • 컴파일 시점에 객체의 이름을 정의해야 합니다
  • 컴파일 시점에 객체의 크기를 정의해야 합니다.

이러한 이유로 스택 메모리를 컴파일 시점 메모리(compile-time memory)라고 부르기도 합니다. 스택 메모리에 저장할 모든 객체는 컴파일 시점에 확실하게 이름과 크기가 정의되어 있어야 합니다.

#include <iostream>
using namespace std;

int main()
{
	int size;
	cin >> size;
	double array[size]; // 컴파일 오류
	...
	return 0;
}

지역 변수 array를 스택 메모리에 저장하려면, 컴파일 시점에 배열의 크기를 알아야 하기 때문에 컴파일 오류가 발생합니다. 이와 같은 가변 배열을 만들고 싶으면 힙 메모리라는 영역을 사용해야 합니다.

 

5.힙 메모리

프로그램을 컴파일하는 시점에 객체의 크기를 모른다면, 런타임 시점에 메모리에 객체를 만들어야 합니다. 힙 메모리(heap memory)는 런타임 시점에 객체를 저장할 때 사용합니다. 여유 메모리(free memory) 또는 동적 메모리(dynamic memory)라고도 부릅니다.

C++는 스택에 있는 객체만 이름을 가질 수 있습니다. 따라서 힙 메모리의 객체는 자신의 이름을 가질 수 없습니다. 힙 메모리에 생성한 객체는 스택 메모리에 있는 포인터로 가리켜야 합니다. 즉 런타임 시점에 메모리에 객체를 만드는 작업은 스택과 힙을 모두 사용하는 것입니다. 스택 메모리에는 4바이트의 작은 포인터를 만들고 힙 메모리에는 큰 객체를 생성하여 포인터가 큰 객체를 가리키게 합니다.

포인터는 스택 메모리에, 포인트되는 객체는 힙 메모리에 있음!

 

new와 delete 연산자

그럼 런타임 시점에 어떤 코드로 힙에 객체를 만들 수 있을까요? 그리고 사용을 모두 완료해서 더 이상 필요가 없어진 힙에 있는 객체를 어떻게 제거할 수 있을까요?

힙에 메모리 할당과 해제를 위한 연산자

그룹 이름 연산자 표현식 우선 순위 결합방향
단항 객체 할당
배열 할당
객체 제거
배열 제거
new
new[]
delete
delete[]
new type
new type[size]
delete ptr
delete[] ptr
17 ←

참고로 delete를 하면 해당 포인터는 허상 포인터(dangling pointer)가 됩니다. 허상 포인터는 new 연산자를 적용하기 전까지는 사용할 수 없습니다.

/**************************************************************
 * 힙 메모리에 크기가 유동적인 배열을 만들고                  *
 * 포인터로 요소에 접근하는 프로그램                          *
 **************************************************************/
#include <iostream>
using namespace std;

int main()
{
  // 스택에 배열에 대한 크기와 포인터 선언
  int size;
  int* pArray;
  // 사용자로부터 0보다 큰 배열의 크기 입력받기
  do 
  {
    cout << "0보다 큰 배열의 크기를 입력하세요:";
    cin >> size;
  } while(size <= 0);
  // 힙에 배열 생성
  pArray = new int[size];
  // 배열에 값 입력받기
  for(int i = 0; i < size ; i++)
  {
    cout << i << "번째 요소의 값을 입력하세요: ";
    cin  >> *(pArray + i);
  }
  // 배열의 요소 출력
  cout << "배열 내부의 요소:" << endl;
  for(int i = 0; i < size ; i++)
  {
    cout << *(pArray + i) << "   ";
  }
  // 힙에서 배열 제거
  delete [] pArray;
  return 0;      
}

 

힙 메모리와 관련된 문제

힙 메모리, 힙 메모리와 관련된 연산자(new, delete)를 사용할 때는 주의할 점이 있습니다

 

1. 메모리 할당 없이 제거

new 키워드를 사용하지 않았는데 delete 키워드를 사용하는 경우, 즉 힙 메모리에 메모리 할당을 하지 않았는데 제거하려는 경우입니다.

일반적으로 스택에 할당한 객체를 제거하려고 하다가 발생하는 경우가 많습니다.

double x = 23.4; 
double* pX = &x; // 스택에 할당되어 있음
delete pX; // 그런데 힙 메모리에서 제거하므로 런타임 오류가 발생

 

2. 제거 없이 메모리 할당하기(메모리 누수)

메모리 누수는 new 키워드로 힙 메모리 위에 영역을 잡은 뒤, delete 키워드로 제거하지 않았을 때 발생합니다.

double* pX = new double; // 할당된 메모리 사용
...

포인터 변수가 스코프를 벗어나버리면, 포인터 변수가 사라집니다. 따라서 더 이상 해당 메모리 위치를 가리킬 수 있는 방법이 없습니다. 해당 메모리 위치를 제거할 수 있는 방법도 사라집니다. 이를 메모리 누수라고 부릅니다. 메모리 누수가 발생하면 누수가 발생한 메모리 위치를 사용할 수 없으며, 메모리가 부족한 경우에는 시스템에 큰 문제를 야기할 수도 있습니다.

 

3. 허상 포인터

허상 포인터(dangling pointer)는 포인터가 가리키고 있는 객체를 delete 키워드로 제거했는데, 포인터를 활용하려고 할 때 발생합니다.

double* pX = new double;
... // 할당된 메모리 사용
delete pX;
*pX = 35.3; // 허상 포인터 문제 발생

마지막 행에서 오류가 발생합니다. 포인터가 널이므로, 포인터를 사용해서 메모리 위치의 값에 접근할 수 없습니다.

 

 

 

출처 : 포르잔 C++ 바이블

'내일배움캠프 > TIL' 카테고리의 다른 글

[내일배움캠프 Day12] 반복자와 포인터  (2) 2025.01.02
[내일배움캠프 Day11] 템플릿  (3) 2024.12.31
[내일배움캠프 Day9] 포인터  (0) 2024.12.27
[내일배움캠프 Day8] C++ 과제 진행  (2) 2024.12.26
[내일배움캠프 Day7] Git  (1) 2024.12.24
'내일배움캠프/TIL' 카테고리의 다른 글
  • [내일배움캠프 Day12] 반복자와 포인터
  • [내일배움캠프 Day11] 템플릿
  • [내일배움캠프 Day9] 포인터
  • [내일배움캠프 Day8] C++ 과제 진행
개발자 밍
개발자 밍
dev0404 님의 블로그 입니다.
  • 개발자 밍
    Developer
    개발자 밍
  • 전체
    오늘
    어제
    • 분류 전체보기 (88)
      • 강의 (8)
        • UE Climbing System (3)
        • UE Dungeon (1)
        • HCI (4)
      • 책 (18)
        • 객체지향의 사실과 오해 (5)
        • Effective C++ (3)
        • 이득우의 게임 수학 (4)
        • 이것이 취업을 위한 컴퓨터 과학이다 (4)
        • 리뷰 (2)
      • C++ (2)
      • 알고리즘 (2)
      • 자료구조 (1)
      • Unreal (4)
      • 내일배움캠프 (52)
        • TIL (52)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    자료구조
    Effective
    객체지향
    내일배움캠프
    그래픽스
    알고리즘
    언리얼
    c++
    게임수학
    컴퓨터구조
    컴퓨터 구조
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
개발자 밍
[내일배움캠프 Day10] 메모리 관리
상단으로

티스토리툴바