목차
배경
프로세스는 실행 중인 프로그램을 뜻하는데, 여기서 실행 중이라는 뜻은 프로그램이 메인 메모리에 올라갔다라는 의미입니다. 기본적으로 프로세스는 디스크(SSD, HDD...etc)에 프로그램(코드)를 메모리에 불러오는 것입니다.
메인 메모리(RAM)와 레지스터는 오직 CPU만 직접적으로 엑세스할 수 있는 저장장치(Storage) 입니다.
레지스터에 접근하는 것은 1 CPU 사이클 혹은 더 적은 시간 내에 완료되지만 메인 메모리에 접근은 여러 사이클이 걸릴 수 있습니다. 캐시는 메인메모리와 CPU 레지스터 사이에 위치합니다.
프로세스가 메모리에 올라가 있다면 각 프로세스는 자신만의 메모리 공간을 사용해야 합니다. 이를 위한 보호(protection) 방법으로 베이스 레지스터(base register)와 한계 레지스터(limit register)를 사용해서 프로세스의 논리 주소를 정의해 보호해줄 수 있습니다.
CPU는 유저모드에 모든 메모리 접근에서 그 주소가 base와 limit(base+limit) 사이에 있는지 확인하고 잘못된 접근이라면 세그멘테이션 오류(segmentation fault)를 발생시키며 프로그램을 중단합니다.
주소 바인딩(Address Binding)
프로그램은 디스크에 저장되어있는 이진실행파일에 불과합니다. 저희는 코딩을 하면서 해당 변수가, 코드가 메모리 속 어느 위치에 저장할지 작성하지 않았습니다. 그러면 이 파일에 주소는 대체 언제 결정(binding)될까요?
다음 사진은 소스코드를 컴파일하고 실행파일로 만들어 로더를 통해 CPU코어에 실행하는 절차입니다.
- 소스 코드는 일반적으로 symbolic 주소 입니다.(변수나 함수 같이 코드에서 사용하는 상징적인 이름을 주소로 사용)
- 컴파일러는 소스 코드 내의 주소를 재배치(relocatable)가 가능한 주소(논리주소)로 바인드합니다.
- 링커 or 로더(Linker, Loader)는 위 재배치가 가능한 주소를 절대(absolute) 주소로 바인드 합니다.
* Symbolic address : 변수, 함수 같이 코드에서 사용하는 상징적인 이름을 주소로 사용하는 방법
* Logical address : 프로세스마다 독립적으로 갖는 논리주소. relocatable 주소라고도 합니다.
* Physical address : 실제 메모리(물리적인 메모리)위치를 식별하는 주소. 절대 주소라고도 합니다.
정리하면 일반적으로 저희가 작성한 소스 코드는 symbolic 주소인 상태에서 > 컴파일러에 의해 적당히 가공되어 자유롭게 배치가 가능한 논리 주소가 되고 > 프로그램을 실제로 실행하는 실행 시간에 논리 주소를 실제 메모리에 물리적 주소로 변환시킵니다.
* 각 소스코드(.c, .java ...etc)는 각각의 오브젝트 파일과 1:1 매칭됩니다. (컴파일은 1:1 매칭)
* 여러 오브젝트 파일은 하나의 링크와 1:n 매칭됩니다.(링크는 1대다 매칭)
실제로 프로그램의 주소가 결정되는 시기는 다음 3가지 단계에서 생길 수 있습니다.
1. 컴파일 타임 바인딩(Compile time) : 물리적 메모리 주소가 프로그램 컴파일 시기에 결정되는 바인딩 방식입니다.
프로세스의 논리주소와 물리주소가 동일하며 만약 메모리 위치를 바꾸기 위해서는 재컴파일 해야합니다.
2. 로드 타임 바인딩(Load time) : 프로그램 실행이 시작될 때, 로드 타임에 논리주소에 의해 물리주소가 결정됩니다.
로더(loader : 사용자 프로그램을 메모리로 올리는 프로그램)가 메모리 주소를 부여하며 프로그램이 종료될 때 까지 메모리에 고정됩니다.
3. 실행 타임 바인딩, 지연 바인딩(run time) : 프로그램이 실행을 시작한 이후에도 메모리에 주소가 변경될 수 있는 방식입니다.(swapping, paging) 실행 시간 중 주소를 매핑하기 위해서 하드웨어적 도움인 가상 메모리(MMU) 개념이 필요해졌습니다.
논리 vs 물리 주소 공간
논리 주소는 사용자 프로세스에서 쓰기 위해 CPU에 의해 생성되며 가상 주소라고도 합니다. 실제로 저희가 코드에서 주소를 찍으면 나오거나 고수준에서 개발을 하면서 만나는 대부분의 주소는 논리 주소입니다.
물리주소는 메모리에 물리적 주소로 실제 하드웨어 상 주소입니다.
논리 주소와 물리 주소는 컴파일 타임과 로드 타임 주소 바인딩에서는 같은 주소를 갖습니다, 하지만 실행 타임 바인딩 단계에서는 논리 주소와 물리 주소가 다릅니다.
Memory Management Unit(MMU)
MMU는 CPU가 메모리에 접근하는 것을 도와주는 하드웨어 장치로 실시간으로 논리 주소를 물리 주소로 매핑하는 역할을 합니다.
MMU에는 여러 방식이 있지만 가장 간단한 방식으로 논리 주소에 base 레지스터, 이제는 재배치(relocation) 레지스터라고 부를 레저스터의 값을 더하여 실제 메모리에 매핑하는 방법이 있을 수 있습니다. 이때 사용자 프로그램과 CPU는 논리적 주소를 사용하며 실제 물리적인 주소를 전혀 보지 못합니다.
동적로딩(Dynamic Loading)
모든 프로그래밍 실행할 프로그램의 모든 메모리가 필요하지는 않습니다. 일반적으로 큰 규모의 프로그램을 돌릴 때 사용자는 프로그램의 일부 부분에서 주로 시간을 보냅니다. 그래서 효율적으로 메모리를 쓰기 위해 필요할 때마다 로딩하는 방식이 동적 로딩입니다. 이 방식은 OS에 특별한 지원이 필요하지 않습니다.
동적링킹 (Dynamic Linking)
정적 링킹(Static Linking) : 실행 가능한 오브젝트 파일을 만들 때 프로그램에서 사용하는 모든 라이브러리 모듈을 복사하는 방식입니다. 시스템 라이브러리와 프로그램 코드는 로더에 의해 바이너리로 붙여집니다. 이 방식은 중복이 발생할 수 있고, 변화가 생긴 경우 재컴파일로 다시 링킹해야합니다. 장점으로는 속도가 빠르고 모든 코드가 하나의 실행 모듈에 담겨 불일치에 대한 걱정을 하지 않아도 된다고 합니다.(compatibility issues)
동적 링킹(Dynamic Linking) : 동적 링킹은 오브젝트 파일을 만들 때 모든 라이브러리 모듈을 복사하는게 아닌 모듈의 주소만 가지고 있는 상태로 링킹을 실행 시간까지 연기한 후, 런타임에 주소를 타고 가서 필요한 것을 들고오는 방식입니다.
스텁(stub)은 아주 작은 코드 조각으로 라이브러리가 메모리에 상주할 수 있도록 라이브러리 루틴을 찾는데 사용됩니다.
스텁은 모든 라이브러리 루틴에 들어있고, A라이브러리의 b루틴을 호출하면 스텁이 루틴 주소를 자신으로 대체하고 스텁을 참조해 이후에 다이나믹 링킹없이 접근하여 루틴을 실행합니다. 이를 통해 코드를 중복해서 적재하지 않는다고 합니다. 메모리가 효율적이지만 오버헤드가 발생합니다.
동적 링킹은 공유 라이브러리에 적용하기 좋고, 다이나믹 로딩과 달리 다이나믹 링킹과 공유 라이브러리는 OS의 도움이 필요합니다.
메모리 할당
연속 메모리 할당(Contiguous Allocation)
OS와 여러 사용자 프로세스가 메모리를 사용하고, 메모리는 제한되어있기에 효율적으로 쓰고 싶어합니다.
메인 메모리는 보통 2개의 구획(partition)으로 나뉘어 있습니다.
1. 상주하고있는 OS : 일반적으로 낮은 메모리 영역에 인터럽트 벡터 등을 가지고 있습니다.
2. 사용자 프로세스 : 일반적으로 높은 메모리 영역에 있습니다. 각 프로세스는 단일 구역(single section)에 할당되어, 여러 곳에 나뉘어 할당된 것이 아닌, 한 구역에 연속적으로 할당되어 있습니다.
* 논리적으로 연속적인 메모리 내에 있어야 하지만, 물리적으로는 그렇지 않을 수 있습니다.
간단히 생각하면 컴퓨터 시작시 메인 메모리에 OS와 실행 중인 프로그램이 모두 있고, OS가 적절히 논리 주소와 물리 주소를 MMU 등을 이용해 바꾸며 조작합니다.
이때 메모리 보호는 이전 재배치 레지스터와 한계 레지스터를 통해 단일 구역에 접근할 수 있도록 조치됩니다.
가변 파티션(variable partition)
프로세스는 크기가 각각 다르고 메모리에 어떻게 프로세스를 할당하냐에 따라 메모리 효율 차이가 크기 때문에 중요합니다.
가변 파티션에 경우 프로세스 크기에 따라 메모리에 파티션의 크기가 다르기에 위 사진처럼 프로세스를 넣을 수 있고,. 프로세스를 메모리에 할당하고 제거하는 과정이 반복되면 프로세스 사이사이에 빈 공간(Hole)이 생깁니다. 구멍을 계속 방치하면 점점 작은 구멍 여러개로 나뉘어지며 결국 구멍을 한데 뭉치는 과정을 하지 않으면 프로세스를 더 이상 넣을 수 있는 크기에 공간이 없을 것이기에 이 구멍을 어떻게 관리할지가 이슈가 됩니다.
일반적으로 다음과 같은 3가지 방법이 있습니다.
1. First-fit : 프로세스가 들어갈 수 있는 구멍 중 가장 첫 번째 구멍에 일단 들어갑니다.
2. Best-fit : 프로세스가 들어갈 수 있는 모든 구멍 중 가장 작은 구멍에 들어갑니다.
3. Worst-fit : 프로세스가 들어갈 수 있는 구멍 중 가장 큰 구멍에 들어갑니다.
일반적으로 First > Best > Worst 순으로 속도가 빠르고 결국 메모리가 난잡해지면 문제가 생기기에 First-fit을 사용합니다.
단편화 (Fragmentation)
단편화란 메모리에 구멍이나 자료가 조각조각 나뉘는 현상으로 사용 가능한 공간을 줄이거나 읽기 쓰기 수행속도를 늦추는 문제점이 발생합니다.
1. 외부 단편화 (External Fragmentation) : 메모리 공간이 요청을 충족할만한 충분한 공간이 있지만, 그 공간들이 연속적이지 않아 요청을 충족하지 못하게 되는 상태입니다. 예를들어 메모리에 1GB에 여유공간이 있지만 각 공간이 10MB 단위로 쪼개져 있어서 20MB크기에 데이터를 저장하지 못하는 상태입니다.
2. 내부 단편화(Internal Fragmentation) : 할당된 메모리가 요청된 메모리보다 커서 할당된 메모리에서 안쓰이는 메모리 공간에 다른 메모리를 할당할 수 없는 상태를 말합니다. 예를들어 20MB짜리 사진을 저장하는데 30MB 메모리 공간을 줘서 10MB가 남는 것을 말합니다.
*50%의 법칙 : First-fit은 N개의 블록이 할당되었다면 0.5N개의 블록이 조각나서 사용할 수 없다는 분석으로, 이 경우 전체에서 0.5N/(N+0.5N) = 1/3이 못쓰게 된다고 하는 법칙.
연속 메모리 할당에서 외부 단편화 문제를 줄이기 위해 간결화(Compaction)작업을 합니다.
간결화 작업은 메모리 구멍 조각을 모으는 방법으로 오직 메모리 재배치를 동적으로 실행시간에 할 수 있을 때만 진행합니다.
이 때, I/O를 실행중인데 조각모음을 하게 되면 버퍼의 위치가 변경되면서 문제가 발생할 수 있습니다. 예를들어 데이터를 읽는 중 해당 데이터가 다른 곳으로 이동되고 다른 데이터가 읽고있는 위치로 조각모음된 경우 의도와는 다른 I/O가 진행될 수 있습니다. 이에 대한 해결책으로 I/O를 OS 버퍼에서만 수행합니다.
페이징(Paging)
*요약
물리적 주소 공간을 일정 크기로 나눈 블록이 Frame.
논리적 주소 공간을 Frame과 같은 크기로 나눈 블록이 Page.
각 프로세스는 자신의 메모리 페이지를 기록한 페이지 테이블이 존재. 몇번째 페이지, 몇번째 줄로 주소 전달.
CPU는 데이터를 줄(Word)단위로 사용하기에 위와 같이 몇번째 페이지, 몇번째 줄로 데이터를 전달받아 사용
몇 번째 페이지, 몇번째 줄을 표현하는 크기도 Word기 때문에 보통 32비트 CPU면 Word도 32비트, 프로그램 카운터도 32비트.
64비트 CPU는 32비트 OS/애플리케이션도 하위호환으로 사용가능하지만 32비트 CPU는 64비트 프로그램 실행불가
프로세스의 물리적 주소 공간은 불연속적(non-contiguous)일 수 있는 상태로 사용할 때마다 할당하는 방식입니다.
이 방식으로 외부 단편화를 회피할 수 있고, 다양한 크기에 메모리 청크에서 오는 문제를 해결할 수 있습니다.
* 메모리 청크 : 동적으로 메모리를 할당할 때 사용되는 일정한 크기의 메모리 블록(힙 영역에서 쓰는 메모리 블록)입니다.
페이징은 물리 메모리를 고정된 사이즈의 블록(Frame이라 합니다)으로 나눕니다. 이 때 사이즈는 2의 제곱으로 쓰고 512bytes~16 Mbytes가 일반적입니다.
논리 메모리를 프레임과 같은 사이즈로 나눈것을 페이지(Page)라고 합니다. 모든 사용 가능한 프레임을 추적하면서 논리 메모리에 프로그램을 물리 메모리에 올릴 때 프로그램을 통째로 올릴 필요 없이 페이지 조각을 물리 메모리에 올리고 잘 기억하기만 하면 됩니다.
이후 페이지 테이블을 통해 논리 주소를 물리 주소로 바꾸며 접근하면서 논리 메모리 공간과 물리 메모리 공간이 완벽히 분리되어 개발단계에서 물리 주소를 고려하지 않고 개발 가능합니다.
전체적인 장점으로 페이지 규격으로 크기가 고정되고 몇 페이지, 몇 번째 줄 몇 번 단어 등과 같이 상대주소를 쓰며 관리가 편해지지만 아직 외부 단편화 문제는 남아있습니다.
CPU에 의해 생성된 주소는 위와 같이 나뉘는데 주소를 넘겨 줄 때 페이지 번호(p)와 페이지 오프셋(d)만 넘겨주면 됩니다.
CPU는 메모리를 워드(word)단위로 사용하기에 몇 번째 페이지에 몇 번째 줄인지 알려주면 해당 줄을 레지스터로 옮겨 사용할 수 있습니다.
* 워드(Word) : 하나의 instruction이나 연산을 통해 메모리에서 레지스터로 옮겨 놓을 수 있는 데이터 단위. 흔히 32비트 CPU라면 word는 32비트가 됩니다.
프로세스마다 페이지의 개수가 다르기에 페이지 모든 프로세스는 각자 자신의 페이지 테이블을 가지고 있고, OS는 각 프로세스의 페이지 테이블을 관리해줘야 합니다. 페이지 테이블은 PCB(Process Control Block)에 있습니다.
다음은 페이징의 예시 사진입니다. 논리주소는 n = 2, m = 4이며 페이지 사이즈는 4바이트 입니다.물리 메모리는 32바이트(8페이지)입니다. (논리주소 4bits, 물리주소 5bits, 페이지크기 4bytes)
할당되지 않은 프레임은 free-frame list라는 이름의 연결 리스트로 관리하다가 새 프로세스 요청이 들어오면 페이지를 메모리에 할당해줍니다.
페이지 테이블의 경우 계속 크기가 커지면서 페이지 테이블의 시작 주소를 기록하는 PTBR(Page-Table Base Reguster)과 페이지 크기를 보는 PTLR(Page Table Length Register)를 사용합니다. 이 경우 모든 데이터/명령어 접근이 2번의 메모리 접근 과정이 필요하게 되었는데(1번은 페이지 테이블, 1번은 데이터/명령어 접근) 이를 해결하기 위해 특수한 고속탐색 하드웨어 캐시메모리인 TLBs(Translation Look-Aside buffers, also called associative memory)를 마련했습니다.
TLBs는 페이지 번호에 대한 프레임 정보를 TLB에 저장하여 캐싱하는게 기본 원리입니다. 만약 접근하려는 페이지 번호가 TLB에 있다면(TLB hit) 하드웨어적으로 빠르게 물리 주소로 변환하여 찾을 수 있고, 만약 없다면(TLB miss) 기존 과정을 진행합니다.
* TLB TMI
페이지 테이블이 각 프로세스마다 따로 있는 상태에서 context switching이 되면 TLB는 쓸모없는 정보가 됩니다. 그러면 TLB를 모두 flush(수세식)시켜야 합니다. 이를 최소화하기 위해 프로세스의 테이블 정보를 같이 저장하여 사용하고 이를 ASIDs(Address Space identifiers)라고 합니다.
또한 context switching 과정으로 TLB miss가 발생하며 생기는 오버헤드를 TLB Flushing이라 합니다.
일부 TLB는 메모리에 상주할 수 있습니다. 이를 제거할 수 없다(wired down)이라 되어있는데 일반적으로 주요한 커널 코드의 엔트리는 wired down 되어 있습니다.
어떤 CPU는 instruction TLB와 data TLB를 별도로 제공하기도 합니다.
TLB는 계층구조를 가지기도 합니다.
TLB는 병렬 검색을 하며 TLB lookup은 instruction pipeline의 일부이기 때문에 성능 손일이 극히 적습니다.
유효 메모리 접근 시간(EAT : Effective Access Time)은 TLB hit이 얼마나 잘 됐냐에 따라 달라집니다.
메모리 보호(Memory Protection)
읽기 전용, 읽기 쓰기 허용 등 메모리 접근 허용을 표시하는 보호 비트(Protection bit)를 각 프레임에 연결해주며 메모리 보호를 구현할 수 있습니다. 비트를 추가하며 추가 사항들에 대한 허용 여부도 표시할 수 있습니다.
유효/무효 비트(valid/invalid bit)를 각 프레임에 추가하여 메모리 접근이 유효한 접근인지 아닌지를 확인할 수 있습니다.
어떤 비트가 유효한 비트면 페이지가 프로세스의 논리 주소 공간에 포함된다는 뜻이고 합법(legal)한 페이지라고 합니다.
반대로 무효한 비트면 페이지가 논리 주소 공간에 포함되지 않고, 불법(illegal)한 비트라고 합니다. 불법한 주소에 접근하는 경우 OS는 일반적으로 예외 처리 또는 트랩을 발생시킨다고 합니다.
공유 페이지(Shared Pages)
서로 다른 프로세스가 같은 물리적 페이지를 공유하는 방식입니다. 몇몇 OS는 공유 페이지를 통해 공유 메모리를 구현하기도 합니다. 표준 C 라이브러리(libc)에 경우 공유 페이지를 실제 사용하는 사례입니다. 여러 프로세스가 쓰는 코드가 *재진입 가능한 코드(reentrant code)라면 복사보다 공유를 하는 것이 효율적입니다.
* 재진입 가능한 코드(reentrant code) : 메모리 내 동일한 사본이 다중 사용자들에 의해 공유될 수 있도록 작성된 프로그램이나 루틴을 말합니다.
페이지 테이블 구조
32비트 논리주소 공간을 쓰는 컴퓨터에서 페이지 사이즈가 4KB(2^12)라면 페이지 테이블은 2^20(2^32/2^12)개의 엔트리를 가질 수 있습니다. 각 엔트리가 4바이트라면 각 프로세스는 4*2^20 = 4MB가 페이지 테이블의 크기가 됩니다
.페이지 테이블이 커진 만큼 페이지 테이블이 구조화 되고 여러 방식이 있습니다.
● 계층적 페이징
페이지 테이블의 엔트리가 페이지 테이블이고 계층적으로 되어있는 구조입니다. 페이지 테이블이 너무 커질 때 묶어서 관리합니다.
예를들어 32비트 머신에 4k 페이지 사이즈가 페이지 번호는 20bit, 페이지 오프셋이 12인 경우, 페이지 번호를 또 계층적으로 나눌 수 있습니다.
그런 경우 다음같이 페이지를 찾을 수 있습니다.
현재의 경우 64비트 논리주소 공간을 쓰고 있기 때문에 2레벨 계층방식은 충분하지 않습니다. 하지만 반대로 계층이 너무 많으면 또 계층에 대한 관리로 쉽지 않습니다.
64비트 아키텍처에서 계층적 페이지 테이블을 사용하는 것은 계층이 늘어나서 어려움이 따릅니다.Intel x86-64의 경우 64비트 중 48비트만 논리주소로 사용하고 뒤에 16비트는 사용하지 않습니다. 다른 여러 아키텍처도 동일합니다.
48비트 중 일반적으로 4KB(2^12)크기의 페이지 사이즈를 쓰고 남은 36비트를 4계층으로 나눠 각 계층당 9비트, 총 4계층 페이지 테이블을 사용합니다.
관리와 사용에 용이하지만 단점 중 하나로 TLB miss인 경우 계층을 따라 총 5번 메모리 접근을 해야합니다.
● 해시 페이지 테이블
가상 페이지 번호를 페이지 테이블에 해시한 후 넣는 방식입니다. 일반적으로 32비트를 초과하는 주소 공간에서 쓰입니다. 64비트 주소에서는 clustered page tables로 확장됩니다.
위 그림과 같이 페이지 번호가 해싱되어 해시 테이블에 있고, 해시 테이블 각 항목은 연결 리스트를 가지고 있습니다. 연결리스트는 3개의 필드를 가지고 있는데 1. 가상 페이지 번호, 2. 매핑되는 프레임 번호, 3. 다음 엔트리 포인터를 가지고 있습니다. 일반적으로 해시는 input이 달라도 output이 같을 수 있고(해시 충돌) 해결방법으로 Chaining을 사용한 것 같습니다.
● 역 페이지 테이블(Inverted Page Table)
프로세스마다 페이지 테이블을 가지지 않고 물리적 페이지를 직접 관리하는 방법입니다. 전체 테이블에 pid를 붙여서 해당 프로세스에 맞는 페이지를 찾는 방식입니다. 테이블을 전체 1개만 가지니 메모리가 감소하지만 탐색이 힘들어집니다.
하나의 물리적 주소에 하나의 가상메모리 주소만 매핑되기 대문에 페이지 테이블과 같은 메모리 공유는 불가능합니다. 그래서 공유 메모리 구현이 어렵다는 단점이 있습니다.
스와핑(Swapping)
스와핑이란 메모리 부족 등으로 인해 메모리에 내용을 일시적으로 보조기억장치(SSD, HDD 등 backing store)으로 이동시키는 작업입니다. 보조기억장치를 이용해서 총 물리 메모리 공간은 실제 물리 메모리 크기를 넘을 수 있습니다. 하지만 일반적으로 스와핑 단계까지 오면 컴퓨터는 너무 느려서 못 쓸 수준입니다. 메모리를 늘리는게 가장 편한 방법입니다.
스왑됐을때 고려해야 할 사항이 있습니다. 만약 스왑-out 된 프로세스가 다시 스왑 back되어 메모리로 돌아올 때, 나가기 전과 같은 물리 주소에 들어가야하는지 고려해야합니다. 일반적으로 반드시 동일할 필요는 없으나, I/O 버퍼와 같이 주소 바인딩에 따라 요구될 수도 있습니다.
스와핑도 종류가 있습니다. 일반적으로 말하는 스와핑은 Standard Swapping을 뜻합니다.
Standard Swapping : 프로세스 전체를 스와핑합니다.
만약 스와핑을 프로세스가 아닌 페이지 단위로 한다면 페이징이라고 말합니다. (Paging = swapping with paging. 페이지 단위로 스와핑합니다.)
TMI
스와핑이 Context switching 중 필요한 경우 스와핑에 필요한 실제 메모리 용량을 OS에 알려주면 불필요한 스와핑을 줄일 수 있습니다.(request_memory(), release_memory())
Thrashing : 스레싱이란 스와핑이 너무 심해서 작업이 멈춘 것 같은 상태를 말합니다. 메모리가 부족해 스와핑을 하면서 CPU 사용률이 떨어져 OS는 CPU가 놀고 있는 줄 알고 task를 더 할당하고, 그로 인해 메모리는 없으니 더 스와핑을 하면서 반복되는 구조로 컴퓨터 성능이 떨어지는 상태입니다.
SSD는 보통 안에 작은 CPU가 있습니다. SSDㄴㄴ overwrite 불가하고 별도의 erase cycle이 필요해 다른 곳에 copy하고 다 지우는 과정을 거칩니다.
메모리 공간 확보를 위해 모바일에 경우 페이지를 압축하는 방법이 있습니다.
'강의 > OS' 카테고리의 다른 글
OS - 가상 메모리 (0) | 2023.07.22 |
---|---|
OS - Deadlock (0) | 2023.07.18 |
OS - 동기화 예시 (0) | 2023.07.17 |
OS - 동기화 툴 (0) | 2023.07.16 |
OS - CPU Scheduling (0) | 2023.07.13 |