프로그램에 메모리가 할당되는 것은 세가지 종류로 나뉜다.
- 정적 메모리 할당
:한번 만들면 프로그램이 끝날 때까지 계속 메모리를 갖고 있는 것들. - 자동 메모리 할당
:변수를 선언하거나 정적 배열을 선언했을 때 블럭 밖으로 나가면 사라지고 다시 메모리가 할당되는것. - 동적 메모리 할당
: 메모리의 낭비를 최소화하기 위해서 프로그램의 실행중(runtime)에 사용할 메모리 공간을 할당하는 것.
#include <iostream>
using namespace std;
int main()
{
int arr[10000000];
return 0;
}
[1] 53110 segmentation fault "/Users/sunho/Desktop/C++workspaces/TBCppStudy/"main
1000만개의 정수형 배열을 생성하고 실행하였더니 오류가 발생된다.
1000만이면 그렇게 큰 숫자도 아닌데 왜 오류가 생길까?
프로그램에서 정적으로 할당하는 메모리는 스택에 들어가는데, 스택은 용량이 작기 때문이다.
반면 동적으로 할당된 메모리는 힙에 들어가고, 힙은 훨씬 크다.
이러한 이유 때문에 메모리 동적 할당을 사용하는 것은 필수적이다.
new와 delete
우리가 OS에게 정수형 하나의 크기만큼 메모리를 가져오는 또다른 방법이 있다.
#include <iostream>
using namespace std;
int main()
{
int *ptr = new int;
*ptr = 13;
return 0;
}
new int는 integer 사이즈에 맞춰서 os에게 메모리를 받아오고 그 메모리 주소를 알려준다.
그렇기 때문에 포인터로 받아줘야 한다.
그다음 더 중요한 것은 할당받은 메모리를 os에게 다시 돌려주는 것이다.
예를들어 빅데이터, 딥러닝 등을 돌리게 되면 컴퓨터 한 대로 감당할 수 없는 데이터의 양을 사용하게 된다.
그래서 일부 작업을 하고, 작업이 끝난다음 메모리를 os에 다시 돌려주고 다시 받아와서 사용해야 하는 경우가 있기 때문이다. 돌려주는 방법은 간단하다.
#include <iostream>
using namespace std;
int main()
{
int *ptr = new int;
*ptr = 13;
cout << uintptr_t(ptr) << endl;
cout << *ptr << endl;
delete ptr;
ptr = nullptr;
if (ptr != nullptr)
{
cout << uintptr_t(ptr) << endl;
cout << *ptr << endl;
}
else { cout << "Could not allocate memory." << endl; }
return 0;
}
// output
022703216
13
Could not allocate memory.
delete ptr을 해주면 os가 알아서 메모리를 걷어가기 전에 프로그램이 먼저 메모리를 반납한다.
주의해야 할 점은 delete를 해줘도 ptr에는 주소가 따로 저장이 되어 있기 때문에 de-referencing을 하게되면 엉뚱한 값이 나올 것이다.
때문에 delete를 한 후에는 ptr에다가 nullptr같은 값을 넣어준다.
delete ptr;
ptr = nullptr;
이렇게 해놓으면 ptr이 의미가 있을 때에만 de-referencing을 하도록 프로그래밍이 되는 것이다.
std::nothrow
아까와는 다른 상황에 필요한 방법이 있다. 다른 프로그램이 메모리를 사용해야되서 이 프로그램이 메모리를 쓸수 없는 경우가 있다.
다른 프로그램이 메모리를 다 쓸때까지 기다렸다가 다시 메모리를 할당받고 싶을때 std::nothrow를 사용한다.
#include <iostream>
using namespace std;
int main()
{
int *ptr = new (std::nothrow) int;
*ptr = 13;
cout << uintptr_t(ptr) << endl;
cout << *ptr << endl;
if (ptr != nullptr)
{
cout << uintptr_t(ptr) << endl;
cout << *ptr << endl;
}
else { cout << "Could not allocate memory." << endl; }
delete ptr;
return 0;
}
이렇게 넣어 놓으면 오류를 발생시키지 않고 쭉 진행하게 된다.
'C++' 카테고리의 다른 글
6-5. 문자열 스타일의 심볼릭 상수 (기호적 상수) (1) | 2024.02.20 |
---|---|
6-4. 포인터 연산, 배열 인덱싱 (0) | 2024.02.20 |
6-3. 포인터와 정적 배열 (1) | 2024.02.18 |
6-2. 포인터의 기본적인 사용법, 널 포인터 (0) | 2024.02.18 |
6-1. C언어 스타일 배열 문자열(strcpy, strcat, strcmp) (0) | 2024.02.17 |