6장. 메모리 계층 구조
지금까지 우리는 컴퓨터를 '명령어를 실행하는 CPU'와 '데이터를 저장하는 메모리'라는 단순한 모델로 다루어 왔습니다. 하지만 이 모델은 현대 시스템이 실제로 동작하는 방식을 반영하지 못합니다.
1. 메모리 시스템의 실체: 계층 구조
실제 메모리 시스템은 각기 다른 용량, 비용, 접근 시간을 가진 저장 장치들의 계층 구조(hierarchy)로 이루어져 있습니다.
- CPU 레지스터: 가장 자주 사용하는 데이터를 보관합니다. (가장 빠름)
- 캐시 메모리: CPU 가까이에서 주기억장치의 데이터 일부를 임시 보관하는 작고 빠른 공간입니다.
- 주기억장치 (RAM): 크고 느린 디스크의 데이터를 임시 보관합니다. + 네트워크
- 디스크 (SSD/HDD): 네트워크로 연결된 다른 기계의 데이터를 임시 보관하기도 합니다. (가장 느림)
이 계층 구조가 효과적으로 동작하는 이유는, 잘 작성된 프로그램은 '지역성(locality)'이라는 특성을 갖기 때문입니다. 즉, 하위 계층보다 상위 계층의 저장 장치에 더 자주 접근하는 경향이 있습니다. 덕분에 시스템은 저렴하고 큰 하위 계층의 비용으로, 빠르고 작은 상위 계층의 속도를 누리는 효과를 얻을 수 있습니다.
Q. 네트워크 통신은 어떻게 할까?
데이터 전송 (Sending)
- 사용자 공간 (User Space)
- 응용 프로그램이 전송할 데이터를 자신의 메모리 공간(User Space)에 생성합니다.
- 시스템 콜 (System Call)
- 프로그램은
send와 같은 시스템 콜을 호출하여, 커널에게 데이터가 저장된 사용자 공간 메모리의 주소와 크기를 전달합니다.
- 커널 공간 (Kernel Space)
- 커널은 응용 프로그램의 메모리(User Space)에서 커널 자신의 메모리 공간에 있는 소켓 버퍼(Socket Buffer)로 데이터를 복사합니다.
- 커널의 네트워크 스택(TCP/IP)은 이 버퍼의 데이터에 TCP, IP 등의 프로토콜 헤더를 추가하여 네트워크 패킷을 만듭니다.
- 하드웨어 전송 (DMA)
- 커널은 네트워크 인터페이스 카드(NIC)에 전송을 명령합니다.
- NIC는 DMA(Direct Memory Access)를 사용하여, CPU의 개입 없이 커널의 소켓 버퍼에서 NIC 자체의 하드웨어 버퍼로 패킷 데이터를 직접 복사합니다.
- NIC는 자신의 버퍼에 있는 데이터를 물리적인 네트워크 회선으로 전송합니다.
데이터 수신 (Receiving)
- 하드웨어 수신
- 목적지의 NIC가 네트워크로부터 데이터를 수신하여 자신의 하드웨어 버퍼에 저장합니다.
- 커널 공간 (DMA & Interrupt)
- NIC는 DMA를 사용하여 자신의 하드웨어 버퍼에 있는 데이터를 메인 메모리의 커널 공간 소켓 버퍼로 복사합니다.
- 복사가 완료되면, NIC는 CPU에 데이터가 도착했음을 알리는 인터럽트(Interrupt)를 발생시킵니다.
- 커널 처리 및 프로그램 재개
- 인터럽트를 받은 커널은 소켓 버퍼의 패킷을 확인하고, 프로토콜 헤더를 제거하여 순수 데이터를 추출합니다.
- 커널은
recv와 같은 시스템 콜을 호출하고 대기 중이던 응용 프로그램을 깨웁니다(Wake-up).
- 사용자 공간 (User Space)
- 커널은 커널의 소켓 버퍼에 있는 데이터를 응용 프로그램이 지정한 사용자 공간 메모리의 버퍼로 복사합니다.
- 이제 응용 프로그램은 자신의 메모리 공간에서 수신된 데이터를 처리할 수 있습니다.
Q. 응용 프로그램이 전송할 데이터를 자신의 메모리 공간(User Space)에 생성한다고 하는데 어쨋든 물리적으로 저장되어야 한다. 어디에 저장될까?
가상 메모리 주소는 논리적인 주소일 뿐이므로, 시스템 콜로 커널에 전달되기 전에 그 데이터는 반드시 실제 물리 메모리(RAM)에 저장되어 있어야 합니다.
이 과정은 페이지 폴트(Page Fault) 메커니즘을 통해 자동으로 처리됩니다.
1. 응용 프로그램의 데이터 준비
프로그램이 "Hello"라는 데이터를 보내려고 자신의 사용자 공간(가상 메모리)에 버퍼를 만듭니다.
2. 실제 메모리에 저장 (페이지 폴트)
프로그램이 그 버퍼에 "Hello"라는 데이터를 쓰려고 하는 순간, 다음과 같은 일이 벌어집니다.
- CPU는 해당 가상 주소에 연결된 실제 물리 메모리가 아직 없다는 것을 확인합니다.
- 페이지 폴트가 발생하여 운영체제에 도움을 요청합니다.
- 운영체제는 비어있는 물리 메모리(RAM) 공간(페이지)을 찾아, 해당 가상 주소와 연결(매핑)시켜 줍니다.
- 이제 프로그램은 그 연결된 실제 메모리 공간에 "Hello" 데이터를 성공적으로 쓸 수 있습니다.
비유: 당신이 "내 주문 배송 시작해주세요!"라고 요청하는 순간(쓰기 시도), 물류 센터 직원(운영체제)이 비로소 실제 택배 상자(물리 메모리)를 가져와 물건을 담고 포장합니다.
3. 시스템 콜 호출
이제 "Hello" 데이터는 가상 주소와 연결된 실제 물리 메모리(RAM)에 존재합니다. 이 상태에서 프로그램은 send 시스템 콜을 호출하며, 커널에 해당 데이터의 가상 주소를 알려줍니다.
커널은 전달받은 가상 주소를 페이지 테이블을 통해 실제 물리 주소로 변환하여, RAM에 저장된 "Hello" 데이터를 읽어갈 수 있습니다.
Q. 커널 자신의 메모리 공간에 있는 소켓 버퍼(Socket Buffer)로 데이터를 복사한다고 하는데, 커널 메모리 공간은 어디에 있을까?
프로그램이 실행될 때, 운영체제는 해당 프로그램을 위해 거대한 가상 주소 공간(예: 64비트에서는 256TB)을 할당합니다. 이 공간은 크게 두 부분으로 나뉩니다.
- 사용자 공간 (낮은 주소 영역):
- 프로그램의 코드, 데이터, 힙, 스택 등이 여기에 위치합니다.
- 각 프로세스마다 독립적이고 격리된 공간입니다.
- 커널 공간 (높은 주소 영역):
- 운영체제 커널의 코드, 데이터, 커널 스택 등이 여기에 위치합니다.
- 이 영역은 시스템의 모든 프로세스에 의해 공유되며, 어느 프로세스에서 시스템 콜을 하든 항상 동일한 커널 공간으로 제어권이 넘어갑니다.
Q. 커널 코드도 사용하려고 했는데 실제 메모리에 없다면 페이지 폴트가 일어나고 보조기억장치에서 필요한 코드를 가져오는걸까?
커널 코드도 똑같이 가상 메모리 시스템 위에서 동작하기 때문에, 실행하려는 커널 코드의 일부가 현재 물리 메모리(RAM)에 없다면 페이지 폴트가 발생하고 보조기억장치(디스크)에서 해당 코드를 가져옵니다.
커널 코드의 메모리 관리
운영체제 커널은 매우 크기 때문에, 모든 코드를 항상 물리 메모리에 올려두는 것은 비효율적입니다. 따라서 커널도 다음과 같이 코드를 나누어 관리합니다.
- 상주 영역 (Resident Area):
페이지 폴트 처리 루틴, 프로세스 스케줄러 등 시스템 운영에 필수적인 핵심 코드입니다. 이 부분은 부팅 시 물리 메모리에 로드된 후, 시스템이 꺼질 때까지 항상 메모리에 상주합니다. 절대로 디스크로 내려가지 않습니다.
- 비상주 영역 (Non-resident / Pageable Area):
파일 시스템 관련 코드, 특정 장치 드라이버, 자주 사용되지 않는 기능 등 필요할 때만 호출되는 코드들입니다. 메모리가 부족해지면 운영체제는 이 영역의 코드들을 보조기억장치의 스왑 공간(Swap Space)으로 내려놓을 수 있습니다.
커널 코드의 페이지 폴트 과정
- 호출: 시스템 콜이나 인터럽트가 발생하여, 현재 물리 메모리에 없는 비상주 영역의 커널 코드를 실행해야 하는 상황이 발생합니다.
- 페이지 폴트: CPU가 해당 코드의 가상 주소에 접근하려 하지만, 페이지 테이블에 유효한 물리 주소 매핑이 없으므로 페이지 폴트가 발생합니다.
- 처리: 항상 메모리에 상주하는 페이지 폴트 핸들러가 실행됩니다.
- 데이터 로딩: 핸들러는 요청된 커널 코드가 디스크의 스왑 공간에 있다는 것을 확인하고, 비어있는 물리 메모리 페이지를 찾아 해당 코드를 디스크에서 읽어옵니다.
- 재개: 페이지 테이블을 업데이트한 뒤, 원래 실행하려던 커널 코드를 다시 실행합니다. 이제는 물리 메모리에 코드가 있으므로 정상적으로 작업이 진행됩니다.
결론적으로, 커널 역시 효율적인 메모리 관리를 위해 사용자 프로그램과 동일하게 요구 페이징(Demand Paging) 방식을 사용하며, 필요할 때만 코드 조각을 메모리에 올리는 방식으로 동작합니다.
Q. 커널 소켓 버퍼도 가상 메모리일까?
커널 공간에 있는 소켓 버퍼(Socket Buffer)도 가상 메모리입니다.
커널 공간과 가상 메모리
- 커널도 가상 메모리 위에서 동작: 운영체제 커널 역시 사용자 프로그램처럼 가상 주소 공간 위에서 실행됩니다. 커널이 사용하는 모든 데이터 구조(PCB, 페이지 테이블, 소켓 버퍼 등)는 커널의 가상 주소를 가집니다.
- 소켓 버퍼의 위치: 소켓 버퍼는 커널이 네트워크 통신을 위해 동적으로 할당하고 관리하는 메모리 덩어리입니다. 따라서 이 버퍼는 커널 공간(가상 메모리의 상위 영역) 안에 생성됩니다.
- 물리 메모리와의 관계: 커널이 소켓 버퍼를 생성하면, 운영체제는 이 커널 가상 주소에 해당하는 실제 물리 메모리(RAM) 페이지를 연결(매핑)합니다. 네트워크 카드가 DMA를 통해 이 버퍼에 접근할 때는, 커널이 알려준 물리 주소를 사용하여 직접 데이터를 읽거나 씁니다.
결론적으로, 사용자 공간과 커널 공간은 모두 하나의 거대한 가상 주소 공간을 나누어 쓰는 것이며, 그 안의 모든 데이터는 페이지 테이블을 통해 실제 물리 메모리에 연결됩니다.
Q. 소켓 버퍼를 생성하면, 운영체제가 커널 가상 주소에 해당하는 실제 메모리에 매핑해준다는데, 쓰려고 하면 페이지 폴트가 일어나는게 아니라 소켓 버퍼를 생성하면 알아서 물리 메모리에 매핑해주는 걸까?
이 경우에는 페이지 폴트가 일어나지 않습니다.
사용자 프로그램이 스택을 사용할 때와, 커널이 소켓 버퍼처럼 내부적으로 메모리를 사용할 때는 동작 방식이 약간 다릅니다.
1. 사용자 공간 (User Space) - 게으른 할당 (Lazy Allocation)
echo 함수의 스택처럼, 사용자 프로그램이 사용할 메모리는 운영체제가 "나중에 진짜 필요하다고 하면 그때 줄게"라는 식으로 동작합니다.
- 동작: 일단 가상 주소 공간만 예약해두고, 프로그램이 그 주소를 처음 쓰려고 할 때 페이지 폴트가 발생하면 그때서야 실제 물리 메모리를 할당하고 매핑합니다.
- 이유: 프로그램이 예약한 공간을 다 쓰지 않을 수도 있기 때문에, 미리 할당해두는 것은 낭비일 수 있습니다.
2. 커널 공간 (Kernel Space) - 즉시 할당 (Eager Allocation)
네트워크 통신을 위한 소켓 버퍼처럼, 커널이 자신의 작업을 위해 메모리를 필요로 할 때는 즉시 물리 메모리를 할당하고 매핑합니다.
- 동작: 커널이 "소켓 버퍼가 필요하다"고 메모리 관리자에게 요청하는 순간, 운영체제는 지체 없이 비어있는 물리 메모리(RAM)를 찾아 커널의 가상 주소와 바로 연결해 줍니다.
- 이유:
- 신뢰성: 커널은 시스템의 핵심입니다. 커널 작업 중에 "메모리가 없어서 페이지 폴트 처리를 못 하겠다"는 상황이 발생하면 안 됩니다.
- 성능: 네트워크 패킷을 처리하는 것처럼 빠른 응답이 필요한 작업 중에 페이지 폴트로 인한 지연이 발생하면 성능이 저하됩니다.
결론적으로, 커널이 소켓 버퍼를 생성할 때는 페이지 폴트를 통해 나중에 할당하는 것이 아니라, 생성하는 시점에 바로 실제 물리 메모리를 찾아 즉시 매핑해주는 것이 맞습니다.
2. 프로그래머가 메모리 계층을 이해해야 하는 이유
메모리 계층은 애플리케이션의 성능에 막대한 영향을 미칩니다. 프로그램이 필요로 하는 데이터가 어디에 저장되어 있는지에 따라 접근 속도가 극적으로 달라집니다.
- CPU 레지스터: 0 클럭 사이클
- 캐시: 4 ~ 75 클럭 사이클
- 주기억장치: 수백 클럭 사이클
- 디스크: 수천만 클럭 사이클!
따라서 프로그래머가 시스템이 어떻게 데이터를 계층 구조 위아래로 이동시키는지 이해한다면, 자신의 데이터가 가능한 한 계층 구조의 상위(빠른 곳)에 머무르도록 프로그램을 작성하여 성능을 크게 향상시킬 수 있습니다.
3. 지역성 (Locality)
이 아이디어의 중심에는 지역성이라는 프로그램의 근본적인 속성이 있습니다.
- 좋은 지역성: 프로그램이 동일한 데이터 항목 집합을 반복적으로 접근하거나, 인접한 데이터 항목 집합에 접근하는 경향.
- 효과: 지역성이 좋은 프로그램은 그렇지 않은 프로그램보다 상위 계층 메모리에서 더 많은 데이터를 가져오므로, 훨씬 더 빠르게 실행됩니다. (예: 행렬 곱셈 알고리즘은 지역성에 따라 성능이 40배까지 차이 날 수 있음)
이 챕터에서 다룰 내용
이 챕터에서는 SRAM, DRAM, ROM, 디스크와 같은 기본 저장 기술과 이들이 어떻게 계층 구조를 형성하는지 살펴봅니다. 특히 애플리케이션 성능에 가장 큰 영향을 미치는 캐시 메모리에 집중할 것입니다. C 프로그램의 지역성을 분석하는 방법과, 이를 개선하는 기법들을 배우게 될 것입니다.
6.1 저장장치 기술
컴퓨터 기술의 엄청난 성공은 저장 기술의 눈부신 발전에 기인합니다.
- 초창기 컴퓨터: 고작 몇 킬로바이트(KB)의 RAM을 가지고 있었습니다.
- 초창기 IBM PC (1982년 이전): 하드 디스크조차 없었습니다.
- IBM PC-XT (1982년): 10 메가바이트(MB) 용량의 디스크가 도입되면서 변화가 시작되었습니다.
- 2015년경: 일반적인 컴퓨터는 1982년에 비해 30만 배 더 많은 디스크 저장 공간을 갖게 되었으며, 저장 용량은 2년마다 2배씩 증가하는 추세를 보였습니다.
6.1.1 랜덤 접근 메모리 (Random Access Memory)
- RAM(Random Access Memory)은 크게 정적 RAM(SRAM)과 동적 RAM(DRAM), 두 종류로 나뉩니다.
1. 정적 RAM (SRAM, Static RAM)
- 특징: 매우 빠르지만, DRAM보다 훨씬 비쌉니다.
- 주요 용도: CPU 칩 내부 또는 외부에 있는 캐시 메모리로 사용됩니다.
2. 동적 RAM (DRAM, Dynamic RAM)
- 특징: SRAM보다 느리지만, 저렴하고 용량이 큽니다.
- 주요 용도: 컴퓨터의 주기억장치(메인 메모리)와 그래픽 카드의 프레임 버퍼로 사용됩니다.
일반적으로 컴퓨터 한 대에는 수십 메가바이트 이하의 SRAM이 있지만, DRAM은 수백 또는 수천 메가바이트(기가바이트)가 장착됩니다.
정적 RAM (Static RAM, SRAM)
SRAM은 각 비트(bit)를 쌍안정(bistable) 메모리 셀에 저장합니다.
1. 구현 방식
- 각 메모리 셀은 6개의 트랜지스터 회로로 구현됩니다.
- 이 회로는 두 개의 서로 다른 안정된 전압 상태 중 하나를 무기한 유지할 수 있는 속성을 가집니다.
2. 쌍안정성 (Bistability)
SRAM 셀의 동작 원리는 거꾸로 선 막대기에 비유할 수 있습니다.
- 안정 상태: 막대기는 왼쪽 또는 오른쪽으로 완전히 넘어져 있을 때 안정적입니다.
- 불안정 상태: 다른 어떤 위치에서는 결국 왼쪽이나 오른쪽 중 한쪽으로 넘어지게 됩니다.
- 준안정 상태 (Metastable): 이론적으로는 수직으로 완벽하게 균형을 잡고 서 있을 수도 있지만, 아주 작은 방해만 있어도 바로 넘어지게 되며 다시는 수직 상태로 돌아오지 못합니다.
3. SRAM의 특징
이러한 쌍안정적인 특성 때문에, SRAM 메모리 셀은 전원이 공급되는 한 그 값을 무기한 유지합니다. 전기적 노이즈와 같은 방해가 발생하더라도, 방해가 사라지면 회로는 다시 원래의 안정된 상태로 돌아갑니다. (DRAM처럼 주기적인 재충전이 필요 없습니다.)
동적 RAM (Dynamic RAM, DRAM)
DRAM은 각 비트(bit)를 축전기(capacitor)에 저장된 전하(charge) 형태로 저장합니다.
1. 구현 방식
- 각 메모리 셀은 하나의 축전기와 하나의 접근 트랜지스터로 구성됩니다.
- 이 단순한 구조 덕분에 DRAM은 매우 고밀도로 만들 수 있습니다. (같은 면적에 더 많은 비트를 저장 가능)
2. DRAM의 단점
- 민감성: SRAM과 달리, DRAM 셀은 빛이나 전기적 노이즈 같은 아주 작은 방해에도 매우 민감합니다. 한 번 방해를 받아 전압이 바뀌면 스스로 복구되지 않습니다. (디지털 카메라의 이미지 센서가 바로 이 원리를 이용한 DRAM 셀 배열입니다.)
- 데이터 누수 및 재충전(Refresh) 필요: 다양한 누설 전류 때문에, DRAM 셀은 10~100 밀리초라는 매우 짧은 시간 안에 저장된 전하를 잃어버립니다. 따라서 메모리 시스템은 데이터가 사라지는 것을 막기 위해, 주기적으로 모든 비트의 값을 읽고 다시 써주는 '재충전(Refresh)' 과정을 반드시 수행해야 합니다.
일반 DRAM
DRAM 칩 내부의 메모리 셀(비트)들은 슈퍼셀(supercell)이라는 단위로 묶입니다.
- d×w DRAM: d개의 슈퍼셀이 있고, 각 슈퍼셀은 w개의 비트로 구성됩니다. (총 d×w 비트 저장)
- 2차원 배열 구조: 이 슈퍼셀들은 다시 r개의 행(row)과 c개의 열(column)로 이루어진 2차원 직사각형 배열 형태로 구성됩니다.
예시: 16×8 DRAM 칩
- d=16 (16개 슈퍼셀), w=8 (슈퍼셀당 8비트), r=4 (4개 행), c=4 (4개 열)
- 각 슈퍼셀의 주소는
(행, 열)의 형태로 표현됩니다. (예: (2, 1))
데이터 접근 방식 (RAS & CAS)
DRAM 칩은 메모리 컨트롤러와 연결되어 데이터를 주고받습니다. 특정 슈퍼셀 (i, j)의 데이터를 읽는 과정은 두 단계로 이루어집니다.
- RAS (Row Access Strobe): 메모리 컨트롤러가 DRAM에 행 주소
i를 보냅니다.
- DRAM의 동작: 해당 행(
i) 전체의 데이터를 내부 행 버퍼(internal row buffer)라는 임시 저장 공간에 복사합니다.
- CAS (Column Access Strobe): 메모리 컨트롤러가 DRAM에 열 주소
j를 보냅니다.
- DRAM의 동작: 내부 행 버퍼에 복사해 둔 데이터 중에서,
j번째 열에 해당하는 슈퍼셀의 내용을 메모리 컨트롤러로 보냅니다.
이처럼 주소를 행과 열, 두 번에 걸쳐 나누어 보내는 방식은 칩의 주소 핀(address pins) 개수를 줄여 칩 설계를 더 작고 저렴하게 만드는 장점이 있습니다. 반면, 두 단계로 접근하기 때문에 접근 시간이 늘어나는 단점도 있습니다.

6.1.3 메모리 모듈 (Memory Modules)
DRAM 칩들은 메인보드의 확장 슬롯에 꽂는 메모리 모듈이라는 형태로 패키징됩니다. 예를 들어, Core i7 시스템은 240핀 DIMM(Dual Inline Memory Module)을 사용하며, 이는 메모리 컨트롤러와 한 번에 64비트(8바이트) 단위로 데이터를 주고받습니다.
1. 메모리 모듈의 구성
메모리 모듈은 여러 개의 DRAM 칩으로 구성되며, 이 칩들이 협력하여 하나의 큰 메모리처럼 동작합니다.
- 예시: 8개의
8M x 8 DRAM 칩을 사용하여 총 64MB 메모리를 구성한 모듈
8M x 8 의미: 칩 하나당 800만(8M)개의 슈퍼셀이 있고, 각 슈퍼셀은 8비트(1바이트)입니다.
- 데이터 저장 방식: 주기억장치의 64비트(8바이트) 데이터 하나는 8개의 DRAM 칩에 1바이트씩 나뉘어 저장됩니다.
- 0번 DRAM 칩: 64비트 중 첫 1바이트 저장
- 1번 DRAM 칩: 다음 1바이트 저장
- ...
- 7번 DRAM 칩: 마지막 1바이트 저장
2. 데이터 접근 과정
메모리 컨트롤러가 특정 주소 A에 있는 64비트 워드를 읽어오는 과정은 다음과 같습니다.
- 주소 변환: 메모리 컨트롤러는 주소
A를 DRAM 칩 내부의 슈퍼셀 주소 (i, j)로 변환합니다.
- 주소 방송 (Broadcast): 메모리 모듈은 이
(i, j) 주소를 모든 DRAM 칩에 동시에 전달합니다.
- 개별 칩 동작: 8개의 DRAM 칩은 각각 자신의
(i, j) 위치에 저장된 8비트 데이터를 출력합니다.
- 데이터 취합: 메모리 모듈의 회로가 이 8개의 칩에서 나온 8비트 데이터들을 모아 하나의 64비트 워드를 구성한 뒤, 메모리 컨트롤러로 반환합니다.
이러한 병렬 구조 덕분에, 시스템은 8비트 단위로 동작하는 DRAM 칩 여러 개를 묶어 64비트 단위로 데이터를 한 번에 주고받는 고속 통신을 할 수 있습니다. 여러 개의 메모리 모듈을 사용하면 주기억장치의 전체 용량을 더 확장할 수도 있습니다.
6.1.4 향상된 DRAM (Enhanced DRAMs)
급속도로 빨라지는 프로세서의 속도를 따라잡기 위해, 제조업체들은 다양한 종류의 DRAM을 개발해 왔습니다. 이들은 모두 기본적인 DRAM 셀 구조를 기반으로, 접근 속도를 향상시키는 최적화가 적용된 것들입니다.
1. FPM DRAM (Fast Page Mode DRAM)
- 개선점: 기존 DRAM은 한 행(row) 전체를 내부 버퍼로 복사한 뒤, 필요한 슈퍼셀 하나만 사용하고 나머지는 버렸습니다. FPM DRAM은 동일한 행에 연속적으로 접근할 때, 매번 행 주소를 다시 보낼 필요 없이 내부 행 버퍼에서 직접 데이터를 꺼내주어 속도를 향상시킵니다.
- 동작: 첫 접근 시에는 행/열 주소(RAS/CAS)를 모두 보내지만, 그 이후 같은 행의 다른 열에 접근할 때는 열 주소(CAS)만 보내면 됩니다.
2. EDO DRAM (Extended Data Out DRAM)
- 개선점: FPM DRAM을 개선한 형태로, 연속적인 열 주소(CAS) 신호 사이의 시간 간격을 더 촘촘하게 줄여 속도를 높였습니다.
3. SDRAM (Synchronous DRAM)
- 개선점: 기존의 비동기식 DRAM들이 사용하던 복잡한 제어 신호 대신, 메모리 컨트롤러와 동일한 외부 클럭 신호에 동기화하여 동작합니다.
- 효과: 더 빠른 속도로 슈퍼셀의 내용을 출력할 수 있습니다. 오늘날 우리가 'RAM'이라고 부르는 것의 기본이 되는 기술입니다.
4. DDR SDRAM (Double Data-Rate SDRAM)
- 개선점: SDRAM을 향상시킨 기술로, 클럭 신호가 올라갈 때와 내려갈 때 모두 데이터를 전송하여(Double Data-Rate) 실질적인 속도를 두 배로 높였습니다.
- 종류: 프리페치(prefetch) 버퍼의 크기에 따라 DDR, DDR2, DDR3, DDR4, DDR5 등으로 발전하며 대역폭을 계속해서 높여왔습니다.
5. VRAM (Video RAM)
- 주요 용도: 그래픽 카드의 프레임 버퍼(화면에 표시할 이미지 정보 저장)에 특화된 메모리입니다.
- 특징:
- 내부 버퍼의 전체 내용을 순차적으로 빠르게 출력하여 화면을 그리는 데 최적화되어 있습니다.
- 메모리에 대한 읽기와 쓰기가 동시에 가능합니다. 이 덕분에 화면에 현재 이미지를 계속해서 표시하는 중(읽기)에도, CPU나 GPU가 다음 장면에 표시할 새로운 이미지 정보를 쓰는(쓰기) 작업이 동시에 이루어질 수 있습니다.
6.1.5 비휘발성 메모리 (Nonvolatile Memory)
SRAM이나 DRAM과 같은 휘발성 메모리는 전원이 꺼지면 정보를 잃어버립니다. 반면, 비휘발성 메모리는 전원이 꺼져도 저장된 정보를 유지합니다.
역사적인 이유로 통칭하여 ROM(Read-Only Memory, 읽기 전용 메모리)이라고 부르지만, 실제로는 여러 번 쓰고 지울 수 있는 종류도 많습니다.
1. ROM의 종류와 발전 과정
ROM은 재프로그래밍(쓰기) 가능한 횟수와 그 방식에 따라 구별됩니다.
- PROM (Programmable ROM)
: 단 한 번만 데이터를 기록할 수 있습니다. 내부의 퓨즈를 높은 전류로 끊어내는 방식으로 데이터를 기록하기 때문에 수정이 불가능합니다.
- EPROM (Erasable Programmable ROM)
: 자외선을 쬐어 데이터를 지우고 다시 쓸 수 있습니다. 약 1,000회 정도 재기록이 가능합니다.
- EEPROM (Electrically Erasable PROM)
: 자외선 장치 없이, 전기 신호만으로 데이터를 지우고 쓸 수 있습니다. 회로 기판에 장착된 상태로 재프로그래밍이 가능하며, 약 10만 번 정도 재기록이 가능합니다.
Q. 부팅 과정은 어떻게 될까?
컴퓨터의 전원을 켜면 CPU는 RAM(주기억장치)이 비어있어 아무것도 할 수 없습니다. 이때 CPU는 미리 약속된 특정 주소로 찾아가는데, 그 주소에 바로 ROM 칩이 연결되어 있습니다.
ROM의 부팅 과정 역할 (BIOS/UEFI)
ROM에 저장된 펌웨어(Firmware), 즉 바이오스(BIOS) 또는 최신의 UEFI가 컴퓨터 부팅의 전 과정을 지휘합니다.
- 전원 ON: 사용자가 컴퓨터 전원 버튼을 누릅니다.
- BIOS/UEFI 실행: CPU는 ROM에 저장된 BIOS/UEFI 코드를 가장 먼저 읽어와 실행합니다.
- POST (Power-On Self-Test): BIOS는 가장 먼저 컴퓨터에 연결된 주요 하드웨어들(RAM, 키보드, 그래픽카드 등)이 제대로 작동하는지 기본적인 점검을 수행합니다. (부팅 시 '삑' 소리가 나는 과정)
- 부팅 장치 탐색: 하드웨어 점검이 끝나면, BIOS는 운영체제(OS)가 설치된 저장 장치(SSD, HDD, USB 등)를 미리 정해진 순서대로 찾습니다.
- 부트로더(Bootloader) 로드: 부팅 가능한 장치를 찾으면, 그 장치의 가장 앞부분에 기록된 부트로더라는 작은 프로그램을 RAM으로 불러옵니다.
- 제어권 이양: BIOS/UEFI의 임무는 여기까지입니다. 이제 RAM으로 올라온 부트로더에게 시스템의 제어권을 넘겨줍니다.
- 운영체제(OS) 로딩: 제어권을 넘겨받은 부트로더가 비로소 하드디스크에 있는 윈도우나 리눅스 같은 운영체제의 핵심(커널)을 RAM으로 불러오기 시작하고, 최종적으로 운영체제가 컴퓨터 전체를 제어하게 됩니다.
Q. 부트 로더란?
부트로더(Bootloader)는 BIOS/UEFI의 다음 단계를 이어받아, 하드디스크나 SSD에 저장된 운영체제(OS)의 핵심(커널)을 주기억장치(RAM)로 불러오는 역할을 하는 작은 프로그램입니다.
부트로더의 주요 역할
BIOS/UEFI는 매우 단순해서, 하드디스크의 첫 번째 구역(MBR/GPT)에서 부트로더를 찾아 실행시키는 역할까지만 합니다. 그 이후의 복잡한 일은 모두 부트로더가 담당합니다.
- 파일 시스템 인식: BIOS와 달리, 부트로더는 NTFS, ext4와 같은 복잡한 파일 시스템을 이해할 수 있습니다.
- 커널 위치 탐색: 파일 시스템을 뒤져서,
vmlinuz(리눅스)나 ntoskrnl.exe(윈도우)와 같은 운영체제 커널 파일이 어디에 있는지 찾아냅니다.
- 커널 로딩: 찾은 커널 파일을 디스크에서 주기억장치(RAM)으로 불러옵니다.
- 제어권 이양: 커널 로딩이 끝나면, 부트로더는 자신의 임무를 마치고 시스템의 모든 제어권을 운영체제 커널에게 넘겨줍니다.
대표적인 부트로더
- GRUB: 리눅스에서 가장 널리 사용되는 부트로더로, 여러 운영체제 중 하나를 선택하여 부팅할 수 있는 메뉴(멀티 부팅)를 제공합니다.
- Windows Boot Manager: 윈도우 운영체제를 부팅하기 위한 부트로더입니다.
2. 플래시 메모리 (Flash Memory)
플래시 메모리는 EEPROM에 기반한 비휘발성 메모리로, 오늘날 가장 중요한 저장 기술 중 하나입니다. 디지털 카메라, 휴대폰, 노트북, 데스크톱, 서버의 SSD(Solid State Disk) 등 거의 모든 전자기기에서 빠르고 내구성 좋은 저장 장치로 사용됩니다.
3. 펌웨어 (Firmware)
ROM 장치에 저장된 프로그램을 종종 펌웨어(firmware)라고 부릅니다. 펌웨어는 하드웨어와 소프트웨어의 중간적 성격을 띠며, 하드웨어 장치를 제어하는 기본적인 소프트웨어 역할을 합니다.
- 예시 1: PC의 BIOS (Basic Input/Output System)
: 컴퓨터 전원을 켤 때 가장 먼저 실행되어, 기본적인 입출력 기능을 담당합니다.
- 예시 2: 장치 컨트롤러
: 그래픽 카드나 디스크 드라이브 컨트롤러 같은 복잡한 장치들도 내장된 펌웨어를 통해 CPU의 입출력 요청을 해석하고 처리합니다.
Q. 펌웨어와 운영체제의 차이점은 뭘까?
가장 큰 차이점은 역할의 범위와 저장되는 위치입니다.
펌웨어는 하드웨어에 내장되어 그 하드웨어만을 위한 기본적인 제어를 담당하는 반면, 운영체제는 하드디스크에 설치되어 컴퓨터 시스템 전체의 자원을 관리하고 사용자를 위한 실행 환경을 제공합니다.
Q. 디바이스 드라이버와 펌웨어의 차이점이 뭘까?
드라이버는 운영체제(OS)에 설치되는 소프트웨어이고, 펌웨어는 하드웨어 장치 자체에 내장된 소프트웨어입니다. 둘은 서로 다른 계층에서 하드웨어를 제어하는 역할을 합니다.
비유: 통역사와 기계 설명서
- 하드웨어: 외국에서 만든 복잡한 기계 (예: 그래픽카드)
- 펌웨어 (Firmware): 기계에 붙어있는 기본 작동 설명서 또는 내장 프로그램. "A 버튼을 누르면 B 모터가 돈다"와 같이 기계의 가장 기초적인 동작을 정의합니다.
- 드라이버 (Driver): 기계를 제어하려는 당신(운영체제)과 기계 사이의 전문 통역사. 당신이 "그림을 그려줘"라고 추상적으로 명령하면, 통역사는 기계 설명서(펌웨어)를 참조하여 기계가 알아들을 수 있는 저수준의 언어("A 버튼 누르고, C 레버 당기기...")로 번역하여 전달합니다.
한눈에 보는 차이점
| 구분 | 디바이스 드라이버 (Driver) | 펌웨어 (Firmware) |
|---|
| 종류 | 소프트웨어 | 하드웨어에 고착된 소프트웨어 |
| 설치 위치 | 운영체제 (OS) 내부 (하드디스크/SSD) | 하드웨어 칩 (ROM, 플래시 메모리) |
| 주요 역할 | OS의 명령을 하드웨어가 이해하도록 번역/중재 | 하드웨어의 기초적인 동작과 제어 |
| 업데이트 | 비교적 쉬움 (소프트웨어 업데이트) | 어려움 (펌웨어 업데이트/플래싱) |
| 비유 | 전문 통역사 | 기계 사용 설명서 |
함께 작동하는 과정 (예: 그래픽카드)
- 게임(응용 프로그램)이 "캐릭터를 화면에 그려라"고 운영체제에 요청합니다.
- 운영체제는 이 요청을 그래픽 드라이버에게 전달합니다.
- 그래픽 드라이버(통역사)는 이 고수준 명령을 그래픽카드가 이해할 수 있는 수많은 저수준 명령어로 번역합니다.
- 이 저수준 명령어들은 그래픽카드에 전달되고, 그래픽카드의 펌웨어는 이 명령어에 따라 GPU 칩과 메모리를 직접 제어하여 최종적으로 화면에 이미지를 그려냅니다.
6.1.6 주기억장치 접근 (Accessing Main Memory)
CPU와 DRAM 주기억장치 사이의 데이터는 버스(bus)라는 공유 전기 통로를 통해 오고 갑니다. CPU와 메모리 간의 데이터 전송은 버스 트랜잭션(bus transaction)이라는 일련의 단계로 이루어집니다.
- 읽기 트랜잭션 (Read Transaction): 주기억장치에서 CPU로 데이터를 가져옵니다.
- 쓰기 트랜잭션 (Write Transaction): CPU에서 주기억장치로 데이터를 보냅니다.
버스의 구성
버스는 주소, 데이터, 제어 신호를 전달하는 병렬 전선들의 집합입니다. 제어선은 트랜잭션을 동기화하고, 현재 수행되는 트랜잭션의 종류(읽기/쓰기, 주소/데이터 등)를 식별하는 신호를 전달합니다.
데이터 읽기/쓰기 과정

읽기 과정 (Load Operation)
예시: movq A, %rax (A 주소의 값을 %rax 레지스터로 로드)
- 주소 전송: CPU가 시스템 버스에 주소
A를 실어 보냅니다. I/O 브릿지는 이 신호를 메모리 버스로 변환하여 전달합니다.
- 데이터 인출: 주기억장치(DRAM)는 메모리 버스에서 주소
A를 읽고, 해당 위치에서 데이터를 가져와 메모리 버스에 실어 보냅니다. I/O 브릿지는 이 데이터를 다시 시스템 버스로 전달합니다.
- 데이터 저장: CPU는 시스템 버스에 실려온 데이터를 읽어서
%rax 레지스터에 복사합니다.
쓰기 과정 (Store Operation)
예시: movq %rax, A (%rax 레지스터의 값을 A 주소에 저장)
- 주소 전송: CPU가 시스템 버스에 주소
A를 실어 보냅니다. 주기억장치는 이 주소를 읽고 데이터가 오기를 기다립니다.
- 데이터 전송: CPU가
%rax 레지스터의 데이터를 시스템 버스에 실어 보냅니다.
- 데이터 저장: 주기억장치는 메모리 버스에서 데이터를 읽어 DRAM의 해당 위치에 저장합니다.