RAM : 메모리 지칭
메모리 구조 (Memory Structure)
- C언어, C++, Java 등의 언어들을 이용하여 코딩을 하고 실행 파일을 실행 시키면 메모리에 로드되면서 코드에서 작성한 동작에 따라 메모리에 데이터들을 쓰고 읽습니다.
- 좀 더 구체적으로 말하자면, 실행 파일을 만들어 실행 파일로 디스크에 저장할 겁니다.
그리고 사용자가 실행파일을 더블클릭(실행) 하면 이를 운영체제에 실행 파일을 실행하도록 요청하는 겁니다.
그러면 운영체제는 프로그램의 정보들을 읽고 메인 메모리에 공간을 할당해줍니다. 그리고 프로그램의 코드(변수, 함수 등)들을 메모리에 읽고 쓰면서 동작 합니다. - 하지만, 앞서 유의할 점은 임베디드 환경과 우리가 일반적인으로 사용하는 PC컴퓨터(x64 등)에서의 환경하고는 조금 차이가 있습니다. 여기서는 모든 예시가 일반적인 환경(OS)에서 사용한다는 가정하에 설명드립니다.
메모리의 구조
[ Text ]
- 텍스트 영역은 아주 쉽게 말하면 코드를 실행하기 위해 저장되어있는 영역
- 흔히 코드 영역이라고 하는데, 프로그램을 실행시키기 위해 구성되는 것들이 저장되는 영역입니다.
- 한마디로 명령문들이 저장되는 것인데, 제어문, 함수, 상수 들이 영역에 저장
[ Data ]
- 데이터 영역은 우리가 작성한 코드에서 전역변수, 정적 변수 등 저장되는 공간입니다.
- 이들의 특징을 보면 보통 메인(main)함수 전(프로그램 실행 전)에 선언되어 프로그램이 끝날 때 까지 메모리에 남아있는 변수들이라는 특징
- 좀 더 구체적으로 말하자면 Data영역도 그게 두가지로 나뉩니다
- 초기화 된 변수 영역(initalized data segment)
- 초기화되지 않은 변수 영역(uninitalized data segment)
- 초기화 되지 않은 변수 영역은 BSS(Block Started by Symbol)이라고도 합니다.
[ Heap ]
- 힙 영역은 쉽게 말해서 ' 사용자에 의해 관리되는 영역'입니다.
- 흔히 동적으로 할당 할 변수들이 여기서 저장된다고 보시면 됩니다.
- 또한 Java나 C++에서 new 연산자로 생성하는 경우 또는 class,참조 변수 들도 Heap영역에 차지하게 됩니다.
다만, 이는 언어마다 조금씩 상이하니 일단은 '동적 할당 영역'이라고 알아두시면 될 것 같습니다. - 그리고 Heap 영역은 대개 '낮은 주소에서 높은 주소로 할당(적재) 됩니다'
[ Stack ]
- 스택 영역은 함수를 호출 할 때 지역변수, 매개변수들이 저장되는 공간입니다.
- 메인(main) 함수안에서의 변수들도 당연 이에 포함됩니다.
그리고 함수가 종료되면 해당 함수에 할당된 변수들을 메모리에서 해제시킵니다.
한마디로 Stack 자료구조의 pop과 같은 기능입니다. - 여러분이 함수를 '재귀' 호출 할 때, 재귀가 깊어져 Stack Overflow 경험해보셨을 겁니다.
이유가 재귀를 반복적으로 호출하면서 Stack 메모리 영역에 해당 함수의 지역변수, 매개변수들이 계속 할당되다가 OS에서 할당해준 Stack영역의 메모리 영역을 넘어버리면 발생하는 오류 - Stack영역은 Heap영역과 반대로 높은 주소에서 낮은 주소로 메모리에 할당 됩니다.
메모리 주소(Memory Address)
- Windows 운영체제 사용자들 대다수가 한 번쯤을 봤을 x86(32비트) 또는 x64(64비트) 가 있습니다.
이 둘의 차이점을 간단하게 말하자면 비트의 너비(폭)이라고 보시면 됩니다.
고속도로에 32개의 차선이 있는데 이를 더 넓혀 64개의 차선으로 만든 것입니다.
직관적으로 말하자면 데이터 처리 단위라고 보시면 됩니다. - 64bit 운영체제가 데이터 처리 단위가 더 많다보니 당연히 CPU처리도 고속화 되고, 새로운 명령어들도 만들 수 있습니다. 그렇다보니 64bit 운영체제에서는 32bit 프로그램을 돌릴 수 있지만, 32bit 에서는 64bit용 프로그램을 돌리 수가 없습니다.
- 메모리 한칸은 1byte의 크기를 갖고 있습니다. 그리고 32bit 운영체제에서는 32개의 비트, 즉 4byte 길이의 주소를 갖습니다.
- 그리고 2³² 까지의 경우의 수가 있으니 4,294,967,296 개의 주소를 가리킬 수 있다는 의미이고, 이는 1btye 크기의 메모리가 4,294,967,296개 까지 인식이 가능하다는 것, 즉 메모리의 최대 크기는 4,294,967,296 byte = 4GB 입니다.
옛날 32bit 운영체제가 대다수인 시절 메모리를 4GB까지 밖에 설치 할 수 없는 이유가 여기서 나옵니다. - 64bit 운영체제는 8byte 이므로 하나의 주소가 8byte 길이의 주소를 갖는다는 것을 알 수 있습니다. 그리고 마찬가지로 2⁶⁴개. 즉,18,466,744,073,709,551,616개의 주소를 가리킬 수 있다는 의미 입니다.
- C 언어에서 포인터(pointer)에 대해 배울 때 포인터는 메모리 공간 주소를 가리키는 변수이고, "모든 포인터는 모두 4byte의 동일한 크기를 갖는다." 라고 배우지만 이는 사실 32bit 운영체제에 한정해서 사실인 것 입니다.
- 위에서 배운 내용을 생각해보면 포인터는 '주소'를 가리키기 때문에 운영체제가 몇비트이냐에 따라 달라집니다. 주소의 길이가 달라집니다. 32bit에서는 포인터의 크기가 4byte라면, 64bit에서는 주소의 길이가 8byte 이기 때문에 당연하게도 포인터의 크기 또한 8byte일 수 밖에 없습니다.
- 다음 설명부터는 64bit를 기준으로 설명하겠습니다.
한 칸의 크기는 1btye
64비트 운영체제는 메모리 한칸의 주소를 64bit로 표현하며 이는 8btye와 같은 의미이고, 메모리 주소를 8btye로 표현하기 때문에 포인터(주소를 가리키는 변수)의 크기 또한 8byte 이다.
코드와 메모리 영역(Code and Memory Layout)
실제로 어떻게 저장되는지 아주 간단하게 코드와 메모리를 한번 보겠습니다.
- 상수 , 함수는 Text 영역
- 전역, 정적변수 는 Data영역
- 지역변수들은 Stack 영역
- 동적할당이 되는 변수들은 Heap 영역 위치
- 쉽게 생각하면 위 4개의 영역 중 Text영역이 가장 낮은 주소(0에 가까운 주소), Data영역 → Heap 영역 → Stack 영역
1. 상수
- 상수를 int타입으로 값은 30으로 초기화 했습니다.
- 그리고 해당 상소는 메모리 주소는 0x100000e64였죠.(= 0x0000000100000e64)
- int는 4byte의 크기를 갖기 때문에 메모리4간을 차지하게 되고, 보시다시피 해당 메모리 영역에 1E 00 00 00 에 해당 된 것 볼 수 있습니ㅏㄷ.
- 30이 이진수로 0001 1110이고 이를 16진법으로 바꾸면 1E라고 알겁니다.
Buffer Overflow
- 버퍼(Buffer) 를 넘치게(overflow)하게 되는 상태
- Buffer는 보통 메모리를 의미하고 또 다른 말로는 Buffer Overrun 이라고도 합니다.
- Stack 과 Heap은 프로그램이 실행하면서 생성되는 데이터들이 저장되는 공간입니다.
- 해당 영역의 버퍼를 인위적으로 넘치게 만들어 인접한 데이터 영역까지 침법하게 만들고 결국 포인터 영역까지 침법하게 되는데 이 때 특정 명령을 넣어 프로그램을 붕괴시키거나 시스템의 권한을 상승시킬 수 있습니다.
- 물론 영역 간의 침범만이 Overflow 인 것은 절대 아닙니다.
예로 들어 메모리에 할당된 변수의 크기보다 더 큰 데이터를 입력시키는 경우도 Overflow 라고 합나디. C언어에서는 대표적으로 데이터의 크기를 검사하지 않는 함수들인 strcpy(),gets(),scanf() 등 이 있습니다. - 즉, Overflow라는 큰 범주 안에 Heap Overflow, Stack Overflow 들이 있고 그 안에서 데이터 버퍼의 Overflow와메모리 영역에 대한 Overflow 가 있습니다.
- 하지만, 오늘은 메모리에 대한 내용인만큼 '영역'에 초점을 두고 설명하고자 합니다. 그렇기에 Buffer Overflow에 대해 자세히 다루기 보다는, 알고리즘을 풀면서 주로 겪는 경우들을 중심으로 살펴보려고 합니다.
Stack Overflow
- 호출 스택이 할당된 스택 영역 경계석 밖으로 넘어갈 때 발생합니다.
- 보통 가장 흔히 발생하는 경우는 '재귀호출'에서 발생합니다.
Heap Overflow
- 힙 영역에서는 할당된 영역의 경계선 밖으로 넘어갈 때 발생합니다.
- 가장 흔히 발생하는 경우는 매우 큰 데이터를 생성하려고 할 때 발생합니다.
- OutOfMemory 에러, 메모리 부족
- 스택과 마찬가지로 Heap영역보다 큰 데이터가 들어올 경우 발생하는데, Stack에서는 지역변수들이 스택에 쌓인다면, 반대로 Heap영역에서는 동적으로 관리되는 데이터들이 일정 공간 이상 차지하게 될 경우 발생하는 것입니다.
- 각 언어마다 Heap 에서 관리하는 데이터는 조금씩 상이합니다만, 대표적으로 malloc()같은 동적 할당 함수, 객체, 참조변수들이 Heap영역에서 관리됩니다.
- C언어는 new 연산자가 없습니다. 그래서 int[] 같은 배열의 경우 전역, 정적변수가 아닌 Stack영역에 쌓이거나 동적할당을 하고 싶은 경우 malloc() 같은 함수를 씁니다.
- C++나 Java 같은 경우, new 연산자를 지원하고 있어 하나의 객체로 Heap영역에서 관리될 수 있게 하고 있습니다.
출처
https://st-lab.tistory.com/198
'이론' 카테고리의 다른 글
[Javascript] var/let/const 차이 (1) | 2024.09.25 |
---|---|
[Web] DOM이란?(feat. BOM) (0) | 2024.09.25 |
[WEB]WEB(아파치)과 WAS(톰캣) (1) | 2024.09.25 |
[Design Pattern] Singleton Pattern (싱글톤 패턴) 알아보기 (0) | 2024.09.12 |