hello 프로그램의 기계어 인스트럭션들은 원래 하드디스크에 저장되어 있었다. 프로그램이 로딩 될 때 이들은 메인 메모리로 복사된다. printf 로 작동될 데이터 스트링도 본래는 디스크에 저장되어 있었지만 메인 메모리 복사 후 디스플레이 장치로 복사된다.
- 이러한 여러 번의 복사는 프로그램의 “실제 작업”을 느리게 하는 오버헤드이다.
그래서 시스템 설계자들의 주요 목적은 이러한 복사과정들을 가능한 한 빠르게 동작하도록 하는 것이다.
물리학의 법칙으로 인해 더 큰 용량의 저장장치는 작은 용량의 장치에 비해 느린 속도를 갖는다.
- 더 빠른 장치들을 만드는데는 더 느린 장치들보다 상대적으로 비용이 더 필요하다.
- 예시로, 로컬 드라이브는 메인 메모리보다 1,000배 크지만, 1 워드를 읽는데는 천만 배 더 오래걸릴 수 있다.
일반 레지스터 파일은 수백 바이트의 정보를 저장하는 반면, 메인 메모리의 경우는 십억 개의 바이트를 저장한다.
- 그러나 프로세서는 레지스터 파일의 데이터를 읽는 데 메모리보다 100배 가까이 더 빨리 읽을 수 있다.
- 더욱 난감한 것은 기술 발달에 따라 프로세서-메인 메모리 간의 격차가 더 증가하고 있다는 것이다.
프로세서의 성능 향상을 의도하는 것이 메인 메모리의 성능 향상보다 쉽고 비용도 적게 필요하다.
위와 같은 격차에 대응하기 위해 시스템 설계자는 보다 작고 빠른 캐시 메모리라고 부르는 저장장치를 고안했다.
- 프로세서가 단기간이 필요로 할 가능성이 높은 정보를 임시로 저장할 목적으로 탄생했다.
- 아래 그림은 일반적인 시스템에서의 캐시 메모리를 보여준다.
프로세서 칩 내에 들어 있는 L1 캐시는 대략 수천 바이트의 데이터를 저장 할 수 있으며,
거의 레지스터 파일만큼 빠른 속도로 액세스 할 수 있다.
- 이보다 좀 더 큰 L2 캐시는 수백 킬로바이트에서 수 메가 바이트의 용량을 가지며,
프로세서와 전용 버스를 통해 연결된다. - 캐시 시스템의 이면에 깔려있는 아이디어는 프로그램이 지엽적인 영역의 코드와 데이터를 액세스하는 경향인 지역성 (Locality)을 활용하여 시스템이 매우 크고 빠른 메모리 효과를 얻을 수 있다는 것이다.
메모리 계층 구조, 내려갈수록 용량은 커지고, 속도는 느려진다. 또 용량 당 가격이 감소한다.
- Regs, 레지스트리 계열의 저장소를 뜻한다. CPU 내부에 위치한다. 제일 용량이 작고, 제일 빠르다.
- L1 캐시, SRAM으로 구성된 이 캐시는 L(n)캐시 중에서는 제일 빠른 편에 속한다. 대략 수천 바이트의 데이터를 저장 할 수 있다고 알려져있다. 일반적으로, 이 캐시 메모리는 CPU 코어 단위로 배치되어있다.
- L2 캐시, L1 캐시와 마찬가지로 SRAM으로 구성되어 있다. L1, L2 캐시 메모리는 모두 CPU 내부에 위치한다. (L3는 경우에 따라 외부에 위치 할 수도 있다) 최근 CPU는 L1 캐시와 동일하게 L2 캐시도 코어 단위로 분리된 L2 캐시를 제공한다.
- L3 캐시, 캐시 메모리 중 제일 최근에 등장한 개념으로 메인 메모리에서 캐시를 이용하기전 L3 캐시를 가장 먼저 사용하게 된다. 위의 단계 캐시들과 다르게 보통은 여러 코어가 공유하는 메모리이다.
- 여기까지가 CPU 내부 또는 바로 근방에 있는 내용들이다. 아래부터는 보통 사용자가 물리적으로 분리가 가능한 영역으로 나누겠다.
- 메인 메모리, 흔히 램(DRAM)이라고 부르는 부분이 이 곳에 해당된다. 응용 프로그램이 실행되기 전 로컬 디스크에서 이곳으로 프로그램이 적재되어야만 한다.
- DRAM은 주기적으로 데이터를 갱신하기 떄문에 그에 대한 cost로 인해 속도 차이가 또 유의미하게 발생 할 수 있다.
- 로컬 세컨더리 스토리지, 하드 디스크가 보통 이곳에 해당된다. 실행이 가능하나 현재 실행중은 아닌 응용 프로그램들이 주로 저장되며, 다시 말해 적재 전의 내용들이 담긴다. HDD와 SSD가 주된 상품으로 언급되며, 현존하는 로컬 스토리지 중 대중적이며 빠르다고 언급되는 형식은 PCI-E 슬롯을 사용한 저장장치가 있다.
- 물리적 저장장치를 모두 총괄함
- 웹 서버, 분산 파일 처리 시스템, 원격 저장소를 보통 일컫는 내용으로, 로컬이 아니기 때문에 보통은 빠르거나 안정성에 대한 보장은 로컬 세컨더리 스토리지에 비해 어려운게 사실이다. 클라우드 스토리지가 일반적으로 여기에 해당한다.
메모리의 계층 구조의 주요 아이디어는, 한 레벨의 저장장치가 다음 하위레벨 저장장치의 캐시 역할을 한다는 것이다. L1의 캐시는 L2, L2의 캐시는 L3이다. L3 캐시는 메인 메모리의 캐시이고, 이런 식으로 앞에서 언급한 계층 구조를 따라 내려 갈 수 있다.
- 6번 - 7번은 꼭 그렇다라고 할 수 없는 것이, 비용 효율성과 장기 데이터 저장을 목적으로 설계된 계층이다. 어쨌든 아랫 단계에 무언가 저장 할 수 있고 미리 준비 하기 때문에 캐시라고 칠 수는 있겠다.
프로그래머는 전체 메모리 계층 구조에 대한 지식을 활용 할 수 있으며 숙련도가 높다면 저레벨 단위의 최적화를 시도 할 수 있겠다. 파일럿 코는 추가적으로 저레벨 단위의 최적화 방법으로 이러한 방법을 추상적으로 언급했다 :
- 데이터 구조 설계 : 사용이 잦은 데이터를 상위 레벨 캐시에 최적화 하기 위한 알고리즘을 만든다.
- 캐시 친화적 코드 작성 : 연속적인 메모리 접근을 활용하여 공간적 지역성을 극대화를 염두한다.
- 메모리 관리 기술 활용 : 메모리 풀링, 페이지 in/out 관리 기법들을 고려 할 수 있다.
큰 프로그램에 대한 실행 초반의 laggy한 현상은 저레벨 단위의 영역에서 적절한 지역성을 가진 내용들을 찾지 못했기 때문이다. 적절한 데이터를 지역성으로써 판단 할 수 있을 때 laggy한 현상이 해결되는데 기여 할 수 있다. 프로그램을 선택하고 출력하는 과정에서 프로그램은 키보드, 디스플레이, 디스크, 메인 메모리를 직접 액세스 한게 아니다. 운영체제가 제공하는 서비스를 활용해서 그 필요한 내용들을 대신 수행 요청을 했다에 가깝다.
운영체제는 하드웨어와 소프트웨어 사이에 위치한 계층이라고 생각 할 수 있다. (소프트웨어에 가깝다) 응용 프로그램이 하드웨어를 제어하려면, 반드시 운영체제를 거쳐야 한다.
운영체제가 필요한 이유는 크게 두 가지가 있다 :
- 제멋대로 동작하는 응용 프로그램들이 하드웨어를 잘못 사용하는 것을 막기 위해서이다.
- 응용프로그램들이 단순하고 균일한 메커니즘을 사용하여 각기 매우 다른 저수준 하드웨어 장치들을 조작 할 수 있도록 하기 위해서이다.
가상 메모리를 할당하면서 운영체제는 응용프로그램에 해당 가상 메모리에 대한 주소를 넘겨주게 된다.
가상 메모리를 쓰는 것의 의의
- 실제 메모리의 직접 접근을 차단
- 메인 메모리보다 향상된 성능을 꾀함 (로컬 스토리지의 자원 일부를 조정함)
운영체제는 두 가지 목표를 아래 제시된 그림처럼 배치되어 그 목적을 잘 달성하고 있다.
그림에서 프로세스, 가상 메모리, 파일이 무엇을 추상화 했는지를 하나씩 보겠다.
- 프로세스 : 프로세서, 메인 메모리, 입출력장치 모두의 추상화 된 결과이다.
- 일종의 실행 단위로써도 일컫을 수 있다.
- 최신 시스템에서의 프로그램 실행을 할 때, 운영체제는 마치 이 프로그램만 작동하는 것 같은 착각에 빠지게 한다.
- 이러한 flawless한 진행은 전산학에서 다루는 프로세스라는 개념에 의해서 만들어진다.
- 프로세스는 실행 중인 프로그램에 대한 운영체제의 추상화이다.
대부분의 시스템에서 프로세스를 실행 할 CPU의 숫자보다는 프로세스의 갯수가 훨씬 많다. - 이전에는 한 번의 한 개만 실행 할 수 있었지만, 요즘은 멀티코어 프로세서가 여러 개의 프로그램을 동시에 실행 할 수 있다.
프로세서가 프로세스들을 바꿔주는 방식으로, 한 개의 CPU가 다수의 프로세스를 동시에 실행하는 것처럼 보이게 해준다. - 문맥 전환이라는 방법으로 운영체제는 이러한 교차 실행을 수행 할 수 있다.
- 운영체제는 프로세스 실행에 필요한 상태정보의 변화를 추적한다.
- 컨텍스트라고 불리는 상태정보는 Program Counter, 레지스터 파일, 메인 메모리의 현재 값을 가진다.운영체제는 현재 프로세스에서 다른 새로운 프로세스로 제어를 옮기려고 할 때 현재 프로세스의 컨텍스트를 저장한다.
이후, 새 프로세스의 컨텍스트를 복원시키는 문맥 전환을 실행하여 제어권을 새 프로세스에게 넘겨준다. - 새 프로세스는 이전에 중단했던 그 위치부터 다시 실행된다. 그
림을 확인해보면, 문맥 전환이 어떻게 이뤄지는지 간략히 표시한 내용을 확인 할 수 있다.
- 이 그림에는 두 개의 동시성 프로세스가 존재한다.
- 어느 한순간에 단일 프로세서는 한 개의 프로세스의 코드만을 실행 할 수 있다.
- 쉘 프로세스, hello 프로세스
- 처음에는 쉘이 혼자 동작하고 있다가 명령줄에서 입력을 기다린다.
- hello를 실행하라는 명령을 받으면, 쉘은 시스템 콜이라는 특수 함수를 호출한다. 이를 통해 운영체제로 제어권을 넘겨준다.
- 운영체제는 쉘의 컨텍스트를 저장하고 새로운 hello와 컨텍스트를 생성한 뒤, 제어권을 새 hello 프로세스로 넘겨준다.
- - 위의 그림이 나타내듯이, 하나의 프소세스에서 다른 프로세스로의 전환은 운영체제 커널에 의해 관리된다. 커널은 운영체제 코드의 일부분으로 메모리에 상주한다.
- 응용 프로그램이 운영체제에 의한 어떤 작업을 요청하면, 컴퓨터는 특정 시스템 콜을 실행해서 커널에 제어를 넘겨준다. 커널은 요청된 작업을 수행 한뒤 응용프로그램으로 리턴한다. 커널은 별도의 프로세스가 아니라는 점에 유의한다. 커널은 프로세스 관리를 위해 시스템이 이용하는 코드와 자료구조의 집합이다.
- 프로세스 추상화 구현을 위해서는, 저수준의 하드웨어와 운영체제 소프트웨어가 함께 긴밀하게 협력해야 한다hello가 종료되면 운영체제는 쉘의 컨텍스트를 복구시키고 제어권을 넘겨주면서 다음 명령 줄 입력을 기다린다.
- 쓰레드 : 쓰레드는 프로세스를 구성하는 다수의 실행 유닛을 말한다.
- 각각의 쓰레드는 해당 프로세스의 컨텍스트에서 실행되며 동일한 코드와 전역 데이터를 공유한다.
- 쓰레드는 프로그래밍 모델로서의 중요성이 더욱 커지고 있는데, 그 이유는 다수의 프로세스들에서보다 데이터의 공유가 더 쉽다는 점, 쓰레드가 프로세스보다 효율적이라는 점 때문이다.
- 다중 쓰레딩도 다중 프로세서를 활용 할수 있다면 프로그램의 실행 속도를 빠르게 하는 한 가지 방법이다.
- 쓰레드 단위의 컨텍스트 스위칭이 그렇지 않은 것에 비해 속도 향상을 꾀 할 수 있다..
- 가상 메모리 : 메인 메모리와 디스크 입출력 장치의 추상화 결과이다.
- 각 프로세스들이 메인 메모리 전체를 독점적으로 사용하고 있는 것 같은 환상을 제공하는 추상화이다.
- 각 프로세스는 가상주소 공간이라고 하는 균일한 메모리의 모습을 갖게 된다. 리눅스 프로세스들의 가상주소 공간이 하단의 그림에 나타나 있다.
- 최상위 영역 : read, write와 같은 공통 사용 시스템 콜 등이 있다.
- 하위 영역 : malloc와 같은 동적 메모리 할당 코드도 이곳에 있다.
- 말이 좀 이상한데, 선반을 하나 생각해보자. 진짜 중요한건 오른쪽에 놓고, 그냥 별 생각 없이 보관해야 하는 물건은 왼쪽부터 차례대로 채워간다고 생각하면 된다.
- 선반으로 생각하면 더 떠올릴 수 있는게, 선반은 왼쪽부터 채워가면 결국 오른쪽에 있는 중요한 물건까지는 언젠가는 닿는다. 그럼 그런 상황에서 컴퓨터의 대책은 주로 뭐가 있냐하면 :
- 주소 공간 분리 : RAM이 있으면, 여기서 일정량은 최상위 영역 전용으로 배정을 하고 사용자 프로세스의 접근을 완전 차단한다.
- 메모리 보호 기법 : 메모리를 페이지 단위로 관리하는데 접근 권한을 설정 한다. 하위 영역에서 최상위 영역으로 침범 시도시 Page Fault가 발생하며 접근이 차단된다.
- 각 프로세스들에게 보여지는 가상 주소 공간은 몇 개의 정의된 영역으로 구성되어 있다.
- 프로그램 코드와 데이터
- 코드는 모든 프로세스들이 같은 고정 주소에서 시작한다. 다음에 C 전역변수에 대응되는 데이터 위치들이 따라온다. 코드와 데이터 영역은 실행가능 목적파일인 hello로 부터 직접 초기화된다.
- 즉 어느 프로세스를 진행하더라도 코드의 시작점은 배정된 가상 메모리의 일정 위치이다.
- 코드는 모든 프로세스들이 같은 고정 주소에서 시작한다. 다음에 C 전역변수에 대응되는 데이터 위치들이 따라온다. 코드와 데이터 영역은 실행가능 목적파일인 hello로 부터 직접 초기화된다.
- 힙
- 코드와 데이터 영역 다음으로 런타임 힙이 따라온다. 크기가 고정되어 있는 코드, 데이터 영역과 달리, 힙은 프로세스가 실행되면서 C 표준함수인 malloc이나 free를 호출하면서 런타임에 동적으로 그 크기가 늘었다 줄었다 한다.
- malloc을 통해 배정하지만, 런타임 힙은 호출 여부랑 상관없이 기본적인 영역을 생성한다.
- 코드와 데이터 영역 다음으로 런타임 힙이 따라온다. 크기가 고정되어 있는 코드, 데이터 영역과 달리, 힙은 프로세스가 실행되면서 C 표준함수인 malloc이나 free를 호출하면서 런타임에 동적으로 그 크기가 늘었다 줄었다 한다.
- 공유 라이브러리
- 주소공간의 중간 부근에 C 표준 라이브러리나 수학 라이브러리와 같은 공유 라이브러리의 코드와 데이터를 저장하는 영역이 있다. 공유 라이브러리 개념은 강력한만큼 숙지하기엔 난이도가 있다.
- 스택
- 사용자 가상메모리 공간의 맨 위에 컴파일러가 함수 호출을 구현하기 위해 사용하는 사용자 스택이 위치한다. 힙과 마찬가지로 사용자 스택은 프로그램 실행 중에 동적으로 늘어났다 줄어들었다 한다. 특히, 함수를 호출 할 때마다 스택은 커지며, 리턴될 때는 줄어든다.
- 커널 가상메모리
- 주소공간의 맨 윗 부분은 커널을 위해 예약되어 있다. 응용프로그램들은 이 영역의 내용을 읽거나 쓰는 것이 금지되어 있으며, 마찬가지로 커널 코드 내에 정의된 함수를 직접 호출하는 것도 금지되어 있다. 대신, 이런 작업을 수행하기 위해서는 커널을 호출해야 한다.
- 프로그램 코드와 데이터
- 가상 메모리가 작동하기 위해서는 프로세서가 만들어내는 모든 주소를 하드웨어로 번역하는 등의 하드웨어와 운영체제 간의 복잡한 상호작용이 필요하다. 기본적인 아이디어는 프로세스의 가상메모리의 내용을 디스크에 저장하고, 메인 메모리를 디스크의 캐시로 사용하는 것이다.
- 파일 : 입출력장치의 추상화이다.
- 별건 아니고 그저 연속된 바이트들이다. 디스크, 키보드, 디스플레이, 네트워크까지 포함하는 모든 입출력장치는 파일로 모델링한다. 시스템의 모든 입출력은 유닉스 I/O라는 시스테 콜들을 이용하여 파일을 읽고 쓰는 형태로 이루어진다. 그럼에도 불구하고 이 간단하고 고상한 개념은 매우 강력해서, 응용프로그램에 시스템에 들어 있는 다양한 입출력장치들의 통일된 관점을 제공한다.
- 통일된 관점?
- 파일을 읽거나 쓸 때 사용하는 시스템 호출 read, write를 디스크 파일뿐만 아니라 키보드 입력, 네트워크 데이터 송수신에도 사용 할 수 있다.
- 예를 들어, 디스크의 파일 내용을 제어하려는 응용 프로그래머는 다행스럽게도 사용하고 있는 특정 디스크의 기술에 대해서는 잘 알지 못해도 된다. 동일한 프로그램이 다른 디스크 기술을 사용하는 다른 시스템에서도 실행 될 수 있다.
- [Pilot Co.] 그럼 동일한 규약을 이렇게 표현했다고 생각하면 되나?
- 그렇다. 이 규약은 본질적으로 유닉스 시스템의 “모든 것은 파일이다”라는 철학과 직결된다.
그리고 아래와 같은 방식으로 구현 된다 :- 파일 디스크립터 : 각 입출력 장치는 이걸로 식별되며, 이를 통해 자원에 접근하고 사용 할 수 있다.
- 추상화 : 디스크, 소켓, 터미널 등 다양한 장치를 파일로 추상화하여 장시가 실제로 복잡한지 아닌지에 여부를 가능한한 없앨 수 있도록 한다.
- 일관성 : 동일한 시스템 호출을 통해 다양한 종류의 장치를 처리 할 수 있습니다. 이를 통해 개발 및 유지보수를 단순화한다.
- 그렇다. 이 규약은 본질적으로 유닉스 시스템의 “모든 것은 파일이다”라는 철학과 직결된다.
- 통일된 관점?
- 별건 아니고 그저 연속된 바이트들이다. 디스크, 키보드, 디스플레이, 네트워크까지 포함하는 모든 입출력장치는 파일로 모델링한다. 시스템의 모든 입출력은 유닉스 I/O라는 시스테 콜들을 이용하여 파일을 읽고 쓰는 형태로 이루어진다. 그럼에도 불구하고 이 간단하고 고상한 개념은 매우 강력해서, 응용프로그램에 시스템에 들어 있는 다양한 입출력장치들의 통일된 관점을 제공한다.
'컴퓨터 이론 > CS:APP' 카테고리의 다른 글
[CS:APP] 링커 7.1 - 7.14 (0) | 2025.04.18 |
---|---|
[CS:APP] Chap 3.10 - 11 (1) | 2025.04.09 |
[CS:APP] Chap 3.7 - 9 (1) | 2025.04.09 |
[CS:APP] Chap 3.4 - 6 (0) | 2025.04.09 |
[CS:APP] Chap 3.1 - 3 (0) | 2025.04.07 |