비전공자로서 컴퓨터 공학 지식에 대한 목마름이 항상 있었다. 부캠에 들어와서 이런 이론들을 하나씩 공부할 수 있어서 너무 좋다. 이번에는 메모리 구조에 대해서 정리해보려고 한다.
메모리는 컴퓨터를 살때, 용량이랑 버전, 실행클럭 정도만 봤지 이렇게 복잡한 구조가 있다는 것은 알지 못했다. 우선 메모리는 다음과 같은 역할과 구성요소를 가지고 있다.
32bit 운영체제(x86) 혹은 64bit 운영체제(x64)에 따라 메모리 주소가 달라진다. 오늘날의 대부분의 컴퓨터는 64bit 운영체제(x64)를 사용한다.
32bit 운영체제(x86)의 경우 0x00000000 ~ 0xFFFFFFFF(4GB)까지의 주소를 사용한다. 2^32 = 4GB (그래서 예전 컴퓨터들은 메모리를 4GB 이상 장착해도 4GB만 인식했던 것이다.)
64bit 운영체제(x64)의 경우 0x0000000000000000 ~ 0xFFFFFFFFFFFFFFFF(16EB)까지의 주소를 사용한다. 2^64 = 16EB (이론적으로는 메모리를 16EB까지 장착할 수 있다는 것이다.)
둘의 차이가 상당히 크다.
메모리는 한칸에 1byte의 크기를 가지고 있다. (CS50강의에서도 배웠듯)
운영체제별로 다른 것은 메모리 주소의 크기이다.
32bit 운영체제(x86)의 경우 1byte씩 4번을 묶어서 4byte의 크기를 가지는 주소를 사용한다. (4byte = 32bit)
64bit 운영체제(x64)의 경우 1byte씩 8번을 묶어서 8byte의 크기를 가지는 주소를 사용한다. (8byte = 64bit)
요새 대부분의 운영체제는 64bit 운영체제(x64)를 사용한다.
그래서 정리하자면 메모리 한칸의 크기는 1byte이고 64bit 운영체제(x64)의 경우 8byte씩 묶어서 주소를 사용하고, 그렇기 때문에 포인터(주소를 가르키는 변수)의 크기 또한 8byte이다.
아주 중요한 그림이다. 상수, 함수는 Text 영역에, 전역, 정적변수는 Data 영역에, 지역변수들은 Stack 영역에, 동적할당이 되는 변수들은 Heap영역에 위치하게 된다.
Text영역이 가장 낮은 주소, 그다음이 Data영역, 그다음이 Heap영역, 그다음이 Stack영역이다. 이는 포인터로 확인해 볼 수 있다. %p
앞선 네개의 메모리 영역중 가장 대표적인게 Heap과 Stack 영역이다. Heap은 사용자가 직접 메모리를 할당하고 해제하는 영역이고, Stack은 함수의 호출과 함께 할당되며 함수의 호출이 완료되면 소멸하는 영역이기에 프로그램을 실행하면서 생성되고 삭제되기 때문이다.
Buffer Overflow가 뭐냐면, 메모리를 할당할 때 메모리의 크기를 정해주는데, 그 크기를 넘어서 메모리를 할당하려고 할 때 발생하는 것 에러가 Buffer Overflow이다.
이런 Overflow중에 가장 유명한 녀석, Stack Overflow. 말 그대로 Stack영역의 메모리가 넘치면 발생하는 오류다.
호출 스택이 할당 된 스택 영역 경계선 밖으로 넘어갈 때 발생하는데, 보통 가장 흔히 발생하는 경우는 '재귀호출'에서 발생한다.
Heap Overflow는 힙 영역에서 할당 된 영역의 경계선 밖으로 넘어갈 때 발생하는데, 가장 흔히 발생하는 경우는 매우 큰 데이터를 생성하려고 할 때 발생한다. (예를 들어, 1GB짜리 배열을 생성하려고 할 때, 나는 아직 못겪어본듯?)
자바에서는 OutOfMemory 에러, 메모리 부족을 자주 접한다고 한다.
heap overflow를 방지하기 위한 기법중에 가장 유명한 것이 Garbage Collection이다. (자바에서는 자동으로 해준다고 한다. 파이썬도 자동으로 해줌. js도, c나 c++에서는 동적으로 할당한 메모리를 해제해주는 것을 개발자가 직접 해줘야 한다.)
메모리의 역할과 구성에 대해 간단하게 알아보았다. 메모리는 컴퓨터의 가장 핵심적인 요소인 만큼 이것보다 훨씬 복잡한 내용들이 많은 것으로 알고있다. 하지만 당장에 내가 개발을 할때 꼭 알아야 하는 내용은 위의 내용으로 갈음할 수 있을 것 같다.