7-1.[os] 메모리 관리의 개요
메모리 관리의 복잡성
- 과거의 일괄 처리 시스템: 한 번에 한 가지 작업만 처리 -> 메모리 관리가 어렵지 않음
- 오늘날의 시분할 시스템: 운영체제+모든 응용 프로그램이 메모리에 올라와 실행 -> 메모리 관리가 복잡함
메모리 관리의 이중성
프로세스 입장에서 작업의 편리함과 관리자 입장에서 관리의 편리함 이 충돌을 일으키는 것
현대의 메모리 관리 시스템은 프로세스와 메모리 관리자의 상충되는 요구 사항을 완벽하게 처리
충분히 크지 않은 메모리에서 여러 작업을 동시에 실행하는 문제에서 비롯됨
소스코드의 번역과 실행
저급 언어 (low level language): 컴퓨터의 동작을 가장 직접적으로 표현한 언어
고급 언어 (high level language): 사용자가 이해하기 쉽게 프로그래밍할 수 있는 언어
언어 번역 프로그램:
- 고급 언어로 작성한 소스코드를 컴퓨터가 실행할 수 있는 기계어로 번역하는 프로그램
인터프리터: 소스코드를 한 행씩 번역하여 실행한다. (자바스크립트, 베이직)
컴파일러: 소스코드를 컴퓨터가 실행할 수 있는 기계어로 번역한 후 한꺼번에 실행 (자바, C)
컴파일러의 목적
오류 발견
소스코드에서 오류를 발견하여 실행 시 문제가 없도록 하는 것
심벌 테이블(symbol table): 변수 선언부에 명시한 각 변수의 이름과 종류를 모아놓은 테이블
- 선언하지 않은 변수를 사용하지는 않았는지, 변수에 다른 종류의 데이터를 저장하지는 않았는지
코드 최적화
- 군더더기와 사용하지 않는 변수를 삭제하면 더욱 간결해져서 실행 속도가 빨라짐
컴파일러와 인터프리터의 차이
컴파일러: 실행 전에 소스코드를 점검하여 오류를 수정하고 필요 없는 부분을 정리하여 최 적화된 실행 파일을 만든다. 인터프리터: 한 줄씩 위에서부터 아래로 실행되기 때문에 같은 일을 반복하는 경우나 필요 없는 변수를 확인할 수 없다
- 크고 복잡한 프로그램에는 컴파일러를 사용하고 간단한 프로그램에는 인터프리터를 사용
컴파일 과정
소스코드 작성 및 컴파일
- 사용자가 작성한 소스코드(자바, C)를 컴파일러로 번역해서 목적코드(0, 1)를 얻는다
목적 코드와 라이브러리 연결
- 목적 코드가 만들어짐 -> 라이브러리에 있는 코드를 목적 코드에 삽입 -> 최종 실행 파일
- 라이브러리: 자주 사용하는 함수를 시스템 내에 미리 만들어둔 것
동적 라이브러리를 포함하여 최종 실행
- 동적 라이브러리 파일
- DLL (Dynamic Link Loader)
- 함수가 변경되어도 새로 컴파일할 필요가 없다
- 함수가 변경되었을 때는 새로운 라이브러리만 사용하여 실행
- 동적 라이브러리 파일
메모리 관리자의 역할
메모리 관리자
- = Memory Manage Unit = 메모리 관리 유닛
- 가져오기, 배치, 재배치
가져오기 작업
- 프로세스와 데이터를 메모리로 가져오는 작업
배치 작업
- 프로세스와 데이터를 메모리의 어디에 올려놓을지 결정하는 작업
- 작업 전에 메모리를 어떤 크기로 자를 것인지가 매우 중요
재배치 작업
- 꽉 차 있는 메모리에 새로운 프로세스를 가져오기 위해 오래된 프로세스를 내보내는 작업
가져오기 정책
- 프로세스가 필요로 하는 데이터를 언제 메모리로 가져올지 결정하는 정책
- 일반적: 프로세스가 요청할 때 메모리로 가져오는 것
- prefetch: 필요하다고 예상되는 데이터를 미리 가져오는 방법
배치 정책
- 가져온 프로세스를 메모리의 어떤 위치에 올려놓을지 결정하는 정책
- 페이징(paging): 메모리를 같은 크기로 자르는 것을 페이징
- (책의 모든 페이지가 같은 크기인 데에서 유래된 용어)
세그먼테이션(segmentation): 프로세스의 크기에 맞게 자르는 것
배치 정책은 페이징과 세그먼테이션 의 장단점을 파악하여 메모리를 효율적으로 관리할 수 있도록 정책
한정된 메모리를 효율적으로 사용
재배치 정책
- 메모리가 꽉 찼을 때 메모리 내에 있는 어떤 프로세스를 내보낼지 결정하는 정책
앞으로 사용하지 않을 프로세스를 내보내면 시스템의 성능↑ 자주 사용할 프로세스를 내보내면 성능↓
교체 알고리즘: 앞으로 사용하지 않을 프로세스를 찾아서 내보내는 알고리즘