전공/시스템 프로그래밍

[시스템 프로그래밍 12-2강] Memory Management 페이징 기법

뜨거운 개발자 2023. 5. 28. 20:39

Dynamic Memory Allocation

  • 동적할당(일명 힙 할당)은 프로그래밍 언어가 객체를 생성할 때 메모리를 예약하는데 사용하는 기술입니다.
  • 우리가 high level 언어를 쓰다보면 다이나믹 메모리를 할당을 많이 쓴다.(new, malloc등)

실제 C,C++,Java등에는 런타임 힙 관리자가 존재한다.

  • 힙 관리자는 스토리지 할당 및 해제를 위한 프로그래밍 요청을 처리한다.
    • 일반적으로 프로그램이 시작될 때 OS에서 큰 메모리 블록을 할당한다.
    • 스토리지 블록에 대한 Free pointer 목록을 생성한다.
  • 실제로 heap을 사용하는건 어셈블리 언어에서 지원하는게 아니라 윈도우 API를 사용해서 해준다.
  • Window API리스트
  • 따라서 이걸 깊게 들어가지는 않습니다.

GetProcessHeap

  • EAX에 default heap에 대한 핸들을 얻어오는 함수이다.
  • 운영체제가 우리에게 heap메모리 공간을 할당을 해준다. 그것이 default heap이다. (프로세스마다 주어짐)
  • 이 함수를 호출해주면 이 힙의 handle을 받아오는데 handle이라는 것은 일련번호라고 생각하면 된다. (여러개의 힙이 존재하기 때문에 식별하기 위해서)
  • 이 heap에 몇만큼의 크기를 지정해서 할당을 하면 heap의 연속된 공간을 찾아서 반환을 해준다.
  • heap은 멀티 쓰레드로 접근하는 것을 막아뒀다. 그러다 보니 성능상의 문제가 발생한다.
  • 따라서 이것 때문에 성능상의 문제가 발생한다.
  • 따라서 등장한 개념이 private heap이다.
  • 그때 사용하는게 heapCreate

HeapCreate

HeapCreate PROTO,
	flOptions:DWORD,     ;heap allocation options
	dwInitialSuze:DWORD, ;inital heap size, in bytes
	dwMaximumSize:DWORD  ;max heap size in byte
  • 우리가 일반적으로 사용하는 heap은 전부 default 힙이다.
  • 사이즈가 알아서 page에 맞게 크기가 조절된다.
  • 이건 private heap을 생성한다.(eax로 반환)

HeapDestroy

HeapDestroy PROTO,
	hHeap:DWORD,     ;heap handle
  • private heap은 지울 순 있다.

여기서 이 2개의 함수는 이 수업의 범위를 벗어납니다.

HeapAlloc

HeapAlloc PROTO,
	hHeap:DWORD,   ;heap handle to existing heap block
	dwFlags:DWORD, ;heap allocation control flag
	dwBytes:DWORD  ;number of bytes to allocate
  • 기존 힙에서 메모리 블록을 할당하고 eax에 포인터를 반환하는 것이다.
  • 선택적으로 메모리 블록을 모두 0으로 설정하는 HEAP_ZERO_MEMORY로 dwFlags를 설정할 수 있다.

HeapFree

HeapFree PROTO,
	hHeap:HANDLE,
	dwFlags:DWORD,
	lpMem:DWORD
  • free해주는거 당연히 인자는 free할 주소
  • 기본 dwFlags는 NULL이다.

HeapTest Programs

  • 사실 프로그램이 종료되면 default 힙을 윈도우가 회수하긴 한다.

HeapTest Programs2

  • 이건 HEAP 터트리는 경우

x86 Memory Management

용어 설명

  • Multitasking
    • 여러 프로그램을 동시에 실행할 수 있다.
    • 프로세서는 실행중인 모든 프로그램에 시간을 분배한다.
  • 세그먼트 (Segments)
    • 코드 또는 데이터를 포함하는 프로그램에서 사용하는 가변 크기의 메모리 영역
  • Segmentation
    • 메모리 세그먼트를 서로 분리하는 방법을 제공한다.
    • 이를 통해 여러 프로그램을 서로 간섭하지 않고 동시에 실행할 수 있다.
  • Segment descriptor
    • 단일 메모리 세그먼트를 식별하고 설명합니다.
    • 세그먼트의 기본주소, 엑세스 권한, 크기제한, 유형 및 사용법에 대한 정보가 포함되어있다.
  • Segment selector
    • 세그먼트 레지스터에 저장된 16비트 값 (CS,DS,SS,ES,FS,GS)
  • Logical address
    • Segment selector 와 32비트 오프셋의 조합니다.

1. Linear Addresses(운영체제에서 다뤄야 할 내용)

Translating Logical Addresses to Linear Addresses

  • Logical address : Offset과 Selector를 가지고 있다.
    • Offset : 세그먼트의 정보와 얼마나 떨어져 있는지를 보는 것이다.
    • Selector : 세그먼트를 지정해주는 역활을 하고 세그먼트의 번호를 가지고 있다.
  • 디스크립터 태이블: segment의 정보(segment descriptor)들을 가지고 있다.
    • 디스크립터 테이블은 세그먼트의 크기, 코드세그먼트인지 데이터 세그먼트인지 등의 정보를 가지고 있다.
  • 멀티 태스킹 OS에서는 각 프로그램마다 데이터를 위한 고유한 영역이 있다.

X86 프로세서는 1단계 또는 2단계 프로세스를 사용하여 각 변수의 오프셋을 고유주소로 변환한다.

1. 첫번째 단계는 세그먼트 값과 변수의 오프셋을 결합하여 선형 주소(32비트)를 생성.

  • (여기서 선형 주소는 실제 주소일 수 있지만 윈도우나 리눅스에서는 페이징을 사용한다.
  • 디스크립터 태이블을 한번 거쳐야만 한다.
  • 페이징 기법을 사용해서 가상주소를 쓸 수가 있고, 가상 주소 덕분에 윈도우즈는 메모리 램이 매우 큰 범위에 있을 수 있는 것이다.
  • 32비트 선형주소 = 세그먼트의 기본주소 + 32비트 오프셋

2. 두번째 단계는 페이징 변환으로 선형주소를 real address로 변환해준다.

  • 가상의 주소를 실제 주소로 변경하는 과정도 한번 거쳐가는 과정이다.
  • 페이지 변환이란 가상주로를 실제 주소로 변환하는 것이다.

페이징

  • 실제 메모리가 4k로 쪼개져 있는데 그 4k가 기본 단위이고 그것을 페이지라고 부른다.
  • 따라서 선형 메모리 주소체제를 가질 수 있다.
  • 실제 피지컬 메모리는 RAM이다.
    • 보통 피지컬 메모리는 가상메모리보다 작다.
    • 실제로 가상 메모리는 하드디스크에 있다.
    • 당장 사용할 녀석은 다시 램으로 올려놓는다. (운영체제가)
  • 각 프로그램이 실행될 때 프로세서는 비활성 페이지를 메모리에서 선택적으로 언로드하고 즉시 필요한 다른 페이지를 로드한다.
  • OS는 현재 메모리에 있는 모든 프로그램에서 사용하는 페이지를 추적하기 위해서 페이지 디렉토리와 페이지 테이블 세트를 사용한다.
  • 페이지 번역
    • 선형 주소를 실제 주소로 변환
    • 가상 메모리에 있는데 실제 램에 올라오지 않는 경우가 page fault라고 부른다.
    • 운영체제는 프로그램을 재개하기전에 필요한 페이지를 디스크에서 메모리로 복사한다.
    • 이는 가상 메모리 체계이다.
  • 페이징을 사용해서 컴퓨터는 메모리 크기보다 더 크게 프로그램 조합을 실행 할 수 있는 것이다.

Descriptor Tables

  • Global Descriptor Table (GDT)
    • 부팅중에 OS가 프로세스를 보호모드로 전환하면 단일 GDT가 생성된다.
  • Local Descriptor Tables (LDT)
    • 멀티태스킹 OS에서 각 작업 또는 프로그램에는 일반적으로 LDT라고 하는 자체 segment descriptors table이 생성된다.
    • LDTR 레지스터에는 프로그램의 LDT주소가 포함된다.
    • 각 segment descriptor는 선형 주소공간 내의 세그먼트의 기본주소를 포함한다.
    • 이 세그먼트는 일반적으로 다른 모든 세그먼트와 구분되게 태이블에 들어가게 된다.
    • 그림을 보면 해당 세그먼트에 정보가 들어가 있고, 태이블을 보면, 리니어 어드레스가 들어있고 그 리니어 어드레스를 다시 피지컬 어드레스로 매핑을 해주는 전체 과정인 것이다.

Segment Descriptor Details

  1. Base address : 4G 바이트 선형 주소 공간에서 세그먼트의 시작 위치를 정의하는 32비트 정수이다.
  1. Privilege level : 각 세그먼트에서는 0에서 3사이의 권한 수준을 할당할 수 있으며, 0은 일반적으로 OS커널코드에 가장 높은 권한이다.
  1. Segment type : 세그먼트 유형, 엑세스 유형 및 세그먼트가 증가할 수 있는 방향이다.
    • 데이터 세그먼트는 readonly 또는 read/write 일 수 있고 증가/ 감소 할 수 있다.
    • code 세그먼트는 실행전용 또는 실행/읽기 전용일 수 있다.
  1. Segment present flag : 이 비트는 세그먼트가 현재 물리적 메모리에 있는지 여부를 나타낸다.
  1. Granularity flag : 세그먼트 제한 필드의 해석을 결정한다. (0 : 바이트 단위 , 1: 4096바이트 단위
  1. Segment limit : 20비트 정수는 세그먼트의 크기를 지정한다.
    1. Granularity flag is clear : 세그먼트의 크기는 1바이트에서 1메가바이트까지이다.
    1. Granularity flag is set 세그먼트의 크기는 4KBYTE에서 4Gbyte이다.

2. Page Translation

  • 32비트 선형주소는 논리적 주소이기 때문에 32비트 물리적 주소로 변환해주는 것이다.
  • 이 프로세스에는 세가지 구조가 사용된다.
    • 페이지 디렉토리 : 최대 1025개의 32비트 디렉토리 항목 배열
    • 페이지 테이블 : 최대 1024개의 32비트 페이지 테이블 항목 배열
    • 페이지 : 4KByte 또는 4MByte 주소공간이다.
  • 선형 주소는 3개의 필드로 나뉜다.
    • 페이지 디렉토리 항목에 대한 포인터입니다.
    • 페이지 테이블 항목에 대한 포인터이다.
    • 페이지 프레임에 대한 오프셋
  • 제어 레지스터(CR3)에는 페이지 디렉토리의 시작 주소가 포함된다.
  • 리니어 어드레스를 피지컬 어드레스로 변경하는 것
  • 어쨌든 이런게 있어요~~ 개념적으로 가볍게 훑고 넘어가는 것입니다.


Uploaded by N2T

728x90