메모리 관리를 본격적으로 학습하기 전에 메모리 주소에 대해 알아야 합니다.
1. Types of Memory Addresses

메모리 주소 종류에는 Physical address, Logical address, Virtual address라는 것이 있습니다.
먼저 Physical address는 메모리 유닛 하드웨어가 이용하는 주소입니다. 메모리 유닛은 피지컬 어드레스가 주어지면, 그 주소에 나타나는 메모리 반도체 칩에서 바이트 위치를 찾아갈 수 있습니다. 메모리 유닛이 보고 이용하는 물리적인 주소라는 의미이며, 다른 이름으로는 absolute address라고 부릅니다. 쉽게 말하면, 메모리 반도체를 끼웠을 때, 반도체가 1기가면, 0번부터 1기가-1까지 번호가 매겨지는데 그 번호가 Physical address입니다.
그다음에 Logical address는 논리적 연산에 이용되는 주소이고 프로그램 인스트럭션 내에 등장하는 주소입니다. 따라서 인스트럭션 실행하는 프로세서(cpu)가 보고 이용하는 주소입니다. 논리적 주소는 실제 메인 메모리 주소와 보통 다릅니다. 실제 실행하고 싶으면, logical address에 해당하는 실제 physical address를 알아내야 합니다. 이것을 Translation(주소 변환)이라고 합니다.
Virtual address는 가상의 주소라는 것입니다. logical address와 같은 것인데, 다만 virtual memory에서 사용하는 logical address를 virtual address라고 합니다. 가상 메모리는 메인 메모리와 보조기억장치의 공간을 같이 메인 메모리처럼 이용하는 메모리 관리 기술입니다. 보조기억장치까지의 넓은 공간을 프로세스가 사용할 수 있게 하는 기술입니다.
Relative address는 어떤 정해진 위치를 기준으로 해서 상대적인 주소를 매기는 방법입니다.
logical address는 프로세스 시작을 기준으로 해서 얼마만큼 떨어진 곳인지를 표현을 합니다. 따라서 logical address는 relative address가 됩니다.
예를 들어 알아봅시다. 메인 메모리 90,000번지~ 90,100번지에 프로세스 A가 들어있는데, 이러한 90,000대 번지는 physical address이며, 물리적 주소 안에서 프로세스 a에 대해 0번지부터 100번지까지의 번호는 logical (virtual) address가 됩니다. 또한 jump $BA-70에서의 70이 logical address가 되는 것입니다. 또 다른 예가 go to start라는 코드가 있다라고 하면, start는 시작 지점으로 가라는 것이므로 0번지로 점프를 하라는 의미입니다. 0번지는 프로그램 시작 주소를 기준으로 매긴 것입니다. 그래서 relative address가 됩니다. 주소 매기는 방식에 따라서 되는 것이 logical address이고, 같은 의미로 virtual address가 되는 것입니다. virtual address와 logical address는 같은데, virtual address는 virtual memory에서의 logical address를 말합니다.
logical address와 physical address는 관계가 있습니다.
compile-time binding(컴파일 시점 바인딩) 때와 load-time address-binding(로드타임 바인딩) 때는 두 주소가 같습니다.
그러나 execution-time address-binding 때는 두 주소가 다르다는 특징이 있습니다.
이 말이 무엇인지 살펴볼 것입니다.
2. Virtual Address Space

C프로그램을 봅시다. main function이 argument를 전달받고, 그 내부에서 i라는 지역변수와 local_var라는 지역변수를 선언합니다. function밖에 a,b,glob,buf[]를 선언합니다. i를 변경해 출력하는 함수입니다.
이 프로그램을 컴파일하면, 실행파일이 얻어집니다.

gcc와 같은 컴파일러를 사용하면, 디스크에 a.out과 같은 실행파일이 만들어집니다. 이 파일은 앞에 전체 파일에 대한 정보를 가지고 있는 header가 있고, 그 뒤에는 code, data, bss, stack으로 구성이 됩니다. code라는 부분은 변수값을 변화시키고 실제로 인스트럭션을 실행하는 부분입니다. data는 global variable인 a,b,glob,buf[]가 저장됩니다. 다만, 데이터 영역 중 초깃값이 주어지지 않는 buffer인 경우는 bss에 저장되며, 초깃값이 주어진 buffer는 data영역에 buf로 저장됩니다. 그리고 stack에는 local variable이 저장되는 것입니다. 그래서 이러한 실행 파일이 만들어지는데,
이 실행 파일을 실행시키면, 보조기억 장치에 virtual address space가 만들어지는데, 실행파일에 만들어졌던 code, data, bss, stack을 이용하며, 빈 공간으로 구성된 4G바이트이 virtual address space가 만들어집니다. code, data, bss, stack이 메모리로 들어가서 프로세스가 만들어져서 실행되게 됩니다.

4GB는 32bit address computer인 경우, 해당됩니다. 왜 4G가 되는지 알아봅시다. 주소값을 나타내는데 32bit를 쓸 수 있다는 것이므로, 4바이트에 정보가 있는데 그걸로 메모리 주소값을 표현할 수 있습니다. 그 주소값의 가장 작은 값은 32bit가 전부 0이 되면, 그 값은 0입니다. 최댓값은 32bit가 전부 1로 되는 0xFFFFFFFF입니다. F는 15입니다. 그 값을 계산해보면, 2의 32제곱 -1입니다. 2의 32제곱은 2의 2제곱 곱하기 2의 30제곱입니다. 결국, 4 x K x K x K가 되며, 4 x k x M가 되며, 4 x G가 되서 4G가 됩니다. 결국은 전체는 0부터 4G-1까지 존재하는 것입니다. 바이트의 개수는 4G만큼의 주소가 쫙 붙는 것입니다.
크기가 4G만큼의 공간을 virtual address space가 차지하게 됩니다. 가상 주소 공간은 프로세스마다 하나씩 만들어지게 됩니다.

이전에 Process Context에서 봤던 슬라이드를 복습해봅시다. 프로새스 1,2,3이 있을 때, 각각 가상주소공간이 만들어집니다. 모두 크기는 4G입니다. 프로세스1은 보조기억장치에서 실행이 안 되므로 메인 메모리의 어딘가에 들어가서 CPU가 메모리 속 프로세스 내용을 읽을 수 있습니다.
프로그램마다 코드, 데이터의 크기가 다르기 때문에 결국 중간의 안 쓰는 공간은 크기가 다르지만 합치면 모두 4G인 VAS가 프로세스마다 만들어집니다. 그리고 프로세스 1이 실행되기 위해서는 메모리에 들어가서 실행되어야 하며, 보조기억 장치에서는 실행이 안 되므로 code1, data1, stack1이 메인 메모리에 들어가서 자리가 잡히면, cpu가 여기에 있는 내용을 읽어서 실행을 합니다.
프로세스 2번, 프로세스 3번도 마찬가지입니다. 메인 메모리에 직사각형으로 그리고, 커널이 상단에 있고, 프로세스 1,2,3이 차례로 있을 때, 가상주소공간은 보조기억장치에 각각 존재하는 것입니다. 프로세스 1은 80,000번지~100,000번지에 들어있고, 프로세스 2는 100,000번지~150,000번지에 들어있고, 프로세스3은 150,000번지~190,000번지에 들어있습니다. 메모리 할당에 해당하는 것입니다. 프로세스마다 크기에 딱 들어가서 여기 있는 그림은 가변동적할당처럼 보이는 것입니다. 실제로는 뒤에서 배울 paging이라는 방법으로 메모리를 할당하는데, 여기서는 간단하게 3개의 프로세스를 메모리에 표현했습니다.
메인 메모리의 os가 VAS에도 존재합니다. VAS의 kernel은 단지 정보로만 존재하며, 실제로는 디스크 공간을 차지하지 않으며, 메인 메모리의 kernel을 나타내는 것입니다. VAS의 3G~4G-1까지 kernel이 정보로만 존재합니다. 또한, 빈 공간은 공간만 차지하며, 실제로 안 들어온 공간입니다. 또한 VAS에서 code는 실행파일에 있는 코드이므로 실제로는 VAS에서는 stack과 data만 공간을 차지합니다.
VAS의 code는 실행파일에 있는 code와 같으므로 공유하여 메인 메모리에 그게 들어가는데, stack과 data는 VAS에서 가져온 것으로 메인 메모리에 들어갑니다. 그런데 왜 stack과 data는 실행파일에서 VAS로 가져오지 않는 걸까요?
그 이유는 code는 변경되지 않는 부분입니다. stack과 data는 실행파일에 있던 것이 값이 계속 바뀌므로 처음에 복사해서 보조기억장치의 별도의 VAS공간에 잡아줘야 합니다. 그래서 운영체제는 VAS의 각 영역(code, data, bss,stack)의 시작주소와 끝주소(고유주소)를 PCB에 저장합니다. 그래서 정보만 디스크에 실제로 존재하는 것처럼 보이게 만듭니다.

이 그림에서 아까 본 프로세스의 virtual address space인데, page라고 불리우는 작은 단위로 나뉘어졌습니다. 아래의 data영역이 page라고 하는 단위로 구성되었습니다. page가 무엇인지는 다음시간에 배우겠습니다. 마찬가지로 VAS의 0번지~3G-1번지까지는 사용자 프로그램에서 만들어진 code, data, stack이 저장되고, 3G~4G-1번지까지는 kernel이 사용하는 주소공간이며, 그 안에서도 kernel code, kernel data, kernel stack이 있으며, 필요할 때 사용하는 메모리 영역으로 구성됩니다.
커널이 사용하는 이 부분을 실행하고 있을 때, 이것을 system context라고 부릅니다. VAS의 0번지~3G까지를 user context라고 부릅니다. system context와 user context를 합쳐서 process context라고 부릅니다. 이전의 프로세스 관리를 하며 나왔던 내용입니다. user context에 해당되는 0G~3G번지까지 실행하고 있으면, user context를 실행하는 것이며, 그 때를 user mode에서 실행된다고 하며, 3G~4G-1를 실행하고 있는 동안은 system context, 즉 kernel mode에서 실행된다는 것입니다. system context는 즉, 어떤 프로세스 내부에 있는 context의 일부입니다.
어떤 프로세스든 자기 코드 실행하다가 kernel 코드 실행할 수도 있습니다. 자기의 합법적인 주소공간에 있기 때문입니다. 모드를 바꾸는 것을 mode change라고 말했었습니다. 그래서 kernel도 어떤 프로세스 몸체의 일부입니다!!!!!
stack은 data에 연이어 잡지 않고, kernel공간 바로 밑에 잡았으며, kernel바로 밑부터 0층, 1층입니다. 그래서 아래방향으로 자라서 가운데 흰색 부분이 줄어들게 됩니다. 흰색 부분에 library같은 것을 포함시켰을 수도 있고, heap공간은 malloc으로 요청할 수 있는데, 메모리를 동적으로 새로 잡아주면, 그때 heap이라는 메모리 영역을 잡아서 쓸 수 있습니다.
data영역은 위로 커집니다.

리눅스 운영체제에서 가상주소공간에 대해 더 자세히 보인 것입니다. 앞의 그림과 같습니다. 운영체제에서 각 영역의 시작주소와 끝주소를 PCB에 저장한다고 했는데, start_code, end_code, start_data, end_data, brk(heap의 끝부분) 등으로 나타냅니다. 가상주소공간에서 시작을 0번지, 끝을 4G-1번지로 합니다. 즉, 가상 주소 공간은 relative address방식으로 주소를 매기게 되는 것입니다.
또한, shared memory, library들을 포함해서 쓸 경우에는 data영역과 stack사이에 흰색 공간에 잡아두게 됩니다.
'운영체제및실습' 카테고리의 다른 글
| [운영체제및실습]12주차 2회차: 페이징 (0) | 2025.06.01 |
|---|---|
| [운영체제및실습] 12주차 1회차 : Address binding (0) | 2025.05.26 |
| [운영체제및실습] 11주차 4회차: 메모리 파티셔닝 (0) | 2025.05.26 |
| [운영체제및실습] 11주차 3회차: 메모리관리 개요 (0) | 2025.05.25 |
| [운영체제및실습] 11주차 2회차: RAID (0) | 2025.05.25 |