반응형

 

 

 

 

 

1. 이진 탐색 트리란?

 

모든 노드가 아래의 조건을 만족하는 트리 자료구조이다.

key(왼쪽서브트리)≤key(루트노드)≤key(오른쪽서브트리)

- 따라서 이진 탐색 트리를 중위 순회하면 오름차순으로 정렬된 값을 얻을 수 있다.

 

 

 

1) 기본 코드

#include <stdio.h>
#include <stdlib.h>

typedef int element;
typedef struct TreeNode {
    element key;
    struct TreeNode *left, *right;
} TreeNode;

TreeNode * search(TreeNode * node, element key)
{
    if (node == NULL) return NULL;
    if (key == node->key) return node;
    else if (key < node->key)
        return search(node->left, key);
    else
        return search(node->right, key);
}

TreeNode * new_node(element item)
{
    TreeNode * temp = (TreeNode *)malloc(sizeof(TreeNode));
    temp->key = item;
    temp->left = temp->right = NULL;
    return temp;
}

TreeNode * insert_node(TreeNode * node, element key)
{
    if (node == NULL) return new_node(key);

    if (key < node->key)
        node->left = insert_node(node->left, key);
    else if (key > node->key)
        node->right = insert_node(node->right, key);

    return node;
}

TreeNode * min_value_node(TreeNode * node)
{
    TreeNode * current = node;

    while (current->left != NULL)
        current = current->left;

    return current;
}

TreeNode * delete_node(TreeNode * root, element key)
{
    if (root == NULL) return root;

    if (key < root->key)
        root->left = delete_node(root->left, key);
    else if (key > root->key)
        root->right = delete_node(root->right, key);
    else {
        if (root->left == NULL) {
            TreeNode * temp = root->right;
            free(root);
            return temp;
        }
        else if (root->right == NULL) {
            TreeNode * temp = root->left;
            free(root);
            return temp;
        }
        TreeNode * temp = min_value_node(root->right);

        root->key = temp->key;
        root->right = delete_node(root->right, temp->key);
    }
    return root;
}

void preorder1(TreeNode * root) {
    if (root) {
        printf("%d ", root->key);
        preorder1(root->left);
        preorder1(root->right);
    }
}

int max(int a, int b){
    if(a >= b)
        return a;
    else
        return b;
}

int get_height(TreeNode *root){
    int height = 0;

    if(root != NULL){
        height = 1 + max(get_height(root->left), get_height(root->right));}
    
    return height;
}

int get_node(TreeNode *root){
    int count=0;
    if(root != NULL){
        count = 1 + get_node(root->left) + get_node(root->right);
    }
    return count;
}

int get_max(TreeNode *root){
    TreeNode * tmp = root;
    
    while(tmp->right != NULL){
        tmp = tmp->right;
    }
    return tmp->key;
}

int get_min(TreeNode *root){
    TreeNode * tmp = root;
    
    while(tmp->left != NULL){
        tmp = tmp->left;
    }
    return tmp->key;
}

int main(void)
{
    TreeNode * root = NULL;
    char res;
    int value;
    
    printf("Enter i<nsert>,d<elete>,s<earch>,p<rint>,h<eight>,c<ount>,m<ax>,n<min>,q<uit>:");
    scanf("%c", &res);
    
    while(res != 'q'){
        switch (res) {
            case 'i':
                printf("삽입할 값 입력:");
                scanf("%d", &value);
                root = insert_node(root, value);
                break;
            case 'd':
                printf("삭제할 값 입력:");
                scanf("%d", &value);
                root = delete_node(root, value);
                break;
            case 's':
                printf("탐색할 key값 입력:");
                scanf("%d", &value);
                if(search(root, value) == NULL)
                    printf("없음\n");
                else
                    printf("있음\n");
                break;
            case 'p':
                preorder1(root);
                printf("\n");
                break;
            case 'h':
                printf("트리의 높이는 %d\n", get_height(root));
                break;
            case 'c':
                printf("노드의 개수는 %d\n", get_node(root));
                break;
            case 'm':
                printf("가장 큰 값은 %d\n", get_max(root));
                break;
            case 'n':
                printf("가장 작은 값은 %d\n", get_min(root));
                break;
            default:
                break;
        }
        
        fflush(stdin);
        printf("Enter i<nsert>,d<elete>,s<earch>,p<rint>,h<eight>,c<ount>,m<ax>,n<min>,q<uit>:");
        scanf("%c", &res);
    }
    
    return 0;
}

 

 

 

2) 삽입 연산

TreeNode * new_node(element item)
{
    TreeNode * temp = (TreeNode *)malloc(sizeof(TreeNode));
    temp->key = item;
    temp->left = temp->right = NULL;
    return temp;
}

TreeNode * insert_node(TreeNode * node, element key)
{
    if (node == NULL) return new_node(key);

    if (key < node->key)
        node->left = insert_node(node->left, key);
    else if (key > node->key)
        node->right = insert_node(node->right, key);

    return node;
}

 

- 삽입하려는 값이 기준 노드의 값보다 작으면 기준 노드를 왼쪽으로, 크면 기준 노드를 오른쪽 노드로 이동한다. 

- 그러다가 트리의 끝에 도달하면 new_node(); 함수를 사용하여 노드를 삽입해준다.

- 만약, 이미 똑같은 값이 있다면 기존의 트리를 반환할 것이다.

 

 

 

 

 

 

 

 

3) 삭제 연산

 

삭제하려는 노드의 상황은 세 가지가 있다.

① 삭제하려는 노드가 단말 노드인 경우

② 삭제하려는 노드가 하나의 왼쪽 혹은 오른쪽 서브 트리 중 하나만 갖고 있는 경우

③ 삭제하려는 노드가 두 개의 서브 트리를 모두 갖고 있는 경우

 

 

CASE

: 단말 노드이기 때문에 자기 자신과 부모 트리에만 조치를 해 주면 된다.

 

 

 

 

CASE 

: 삭제되는 노드가 왼쪽이나 오른쪽 서브 트리 하나만 가지고 있을 때, 그 노드는 삭제하고 서브 트리를 부모 노드에 붙여준다.

 

 

case  

: 삭제 노드와 가장 비슷한 값을 가진 노드를 삭제 위치로 가져온다. 여기서 비슷한 값은 아래 트리에서 12나 22처럼 왼쪽 서브트리에서 가장큰 수이거나 오른쪽 서브트리에서 가장 작은 수이다.

 

 

 

TreeNode * delete_node(TreeNode * root, element key)
{
    if (root == NULL) return root;

    if (key < root->key)
        root->left = delete_node(root->left, key);
    else if (key > root->key)
        root->right = delete_node(root->right, key);
    else {
        if (root->left == NULL) {	// 단말노드, 오른쪽만 있는 노드
            TreeNode * temp = root->right;
            free(root);
            return temp;
        }
        else if (root->right == NULL) {		// 왼쪽만 있는 노드
            TreeNode * temp = root->left;
            free(root);
            return temp;
        }
        TreeNode * temp = min_value_node(root->right);

        root->key = temp->key;
        root->right = delete_node(root->right, temp->key);
    }
    return root;
}

 

- 기준 노드의 값보다 작으면 왼쪽 노드를, 크면 오른쪽 노드를 반환한다.

- 그러다가 기준 노드의 값과 삭제할 값이 같으면 !

단말노드, 오른쪽 서브트리만 있는 노드는

해당 노드는 삭제하고 오른쪽 서브트리를 부모에게 전달한다.

 

 왼쪽 서브트리만 있는 노드는

해당 노드는 삭제하고 왼쪽 서브트리를 부모에게 전달한다.

 

 왼쪽, 오른쪽 서브트리가 모두 있는 노드는

오른쪽 서브트리에서의 제일 작은 값을 현재 노드 값으로 설정하고, 

오른쪽 서브트리에 내려가서 제일 작은 값을 가지는 노드를 삭제한다.

 

 

 

 

 

 

 

4) 검색 연산

 

TreeNode * search(TreeNode * node, element key)
{
    if (node == NULL) return NULL;
    if (key == node->key) return node;
    else if (key < node->key)
        return search(node->left, key);
    else
        return search(node->right, key);
}

 

- 기준 노드의 값보다 찾는 값이 작으면 왼쪽 서브트리를 반환, 크면 오른쪽 서브트리를 반환한다.

- 값이 같으면 해당 노드를 반환한다.

 

 

 

 

 

5) 기타 연산

: 전위 순회, 트리의 높이 구하기, 노드의 개수, 제일 큰 값, 제일 작은 값

void preorder1(TreeNode * root) {
    if (root) {
        printf("%d ", root->key);
        preorder1(root->left);
        preorder1(root->right);
    }
}

int get_height(TreeNode *root){
    int height = 0;

    if(root != NULL){
        height = 1 + max(get_height(root->left), get_height(root->right));}
    
    return height;
}

int get_node(TreeNode *root){
    int count=0;
    if(root != NULL){
        count = 1 + get_node(root->left) + get_node(root->right);
    }
    return count;
}

int get_max(TreeNode *root){
    TreeNode * tmp = root;
    
    while(tmp->right != NULL){
        tmp = tmp->right;
    }
    return tmp->key;
}

int get_min(TreeNode *root){
    TreeNode * tmp = root;
    
    while(tmp->left != NULL){
        tmp = tmp->left;
    }
    return tmp->key;
}

- 트리의 높이 구하기 : 왼쪽 서브트리와 오른쪽 서브트리 중 더 높이가 높은 길이를 반환한다.

- 노드의 총 개수 구하기 : 루트에서 오른쪽, 왼쪽 내려가면서 NULL 이 아니면 1씩 더해서 총 노드의 개수를 구한다.

 

 

 

 

 

2. 이진 탐색 트리 성능 분석

 

1) 연산의 속도는 트리의 높이 h에 비례한다.

2) 최선의 경우 시간 복잡도 : O(log n)

 

 

3) 최악의 경우 시간 복잡도 : O(n)

 

 

 

 

 

3. 이진 트리의 성질

1) 노드의 개수가 n개이면, 간선의 개수는 n-1개 이다.

2) 높이가 h인 이진트리의 경우,

최소 h개의 노드를 가지며, 최대 2^h - 1 개의 노드를 가진다.

 

3) n개의 노드를 가지는 트리의 높이는

최대 n이고, 최소 [log(n+1)] 이다. -> 올림 기호

 

4) 포화 이진 트리(각 레벨에 노드가 꽉 차있는 이진트리)의 전체 노드 개수는

2^k - 1

-> k 는 높이

 

 

 

 

 

4. 트리의 용어

1) 단말 노드 : 자식이 없는 노드

2) 비단말 노드 : 적어도 하나의 자식을 가진 노드

3) 레벨 : 트리 각 층의 번호

4) 높이 : 트리의 최대 레벨

5) 차수 : 노드가 가지고 있는 자식 노드의 개수 

 

 

 

 

 

 

 

5. 쓰레드 이진 트리란?

: NULL 링크에 중위 순회 시에 후속 노드인 중위 후속자를 저장시켜 놓은 트리이다.

 

 

-> 중위순회 순서 ACBGDFE

 

 

#include <stdio.h>
#define TRUE 1
#define FALSE 0

typedef struct TreeNode {
	int data;
	struct TreeNode *left, *right;
	int is_thread;	// 스레드이면 TRUE
} TreeNode;


//		     G
//	     C		  F
//    A	   B   D     E
TreeNode n1 = { 'A',  NULL, NULL, 1 };
TreeNode n2 = { 'B',  NULL,  NULL, 1 };
TreeNode n3 = { 'C',  &n1,  &n2, 0 };
TreeNode n4 = { 'D', NULL, NULL, 1 };
TreeNode n5 = { 'E', NULL, NULL, 0 };
TreeNode n6 = { 'F', &n4,  &n5, 0 };
TreeNode n7 = { 'G', &n3,  &n6, 0 };
TreeNode * exp = &n7;

TreeNode * find_successor(TreeNode * p)
{
	// q는 p의 오른쪽 포인터
	TreeNode * q = p->right;
	// 만약 오른쪽 포인터가 NULL이거나 p가 스레드이면 오른쪽 포인터를 반환
	if (q == NULL || p->is_thread == TRUE)
		return q;

	// 쓰레드가 아니면, 오른쪽 노드 -> 다시 가장 왼쪽 노드로 이동
	while (q->left != NULL) q = q->left;
	return q;
}

void thread_inorder(TreeNode * t)
{
	TreeNode * q;

	q = t;
	while (q->left) q = q->left;// 가장 왼쪽 노드로 간다.
	do {
		printf("%c -> ", q->data);// 데이터 출력
		q = find_successor(q); // 후속자 함수 호출
	} while (q);			// NULL이 아니면
}
int main(void)
{
	// 스레드 설정 
	n1.right = &n3;
	n2.right = &n7;
	n4.right = &n6;
	// 중위 순회
	thread_inorder(exp);
	printf("\n");
	return 0;
}

 

 

 

- thread_inorder(); 에서 가장 왼쪽 노드로 간다.

- 노드의 값을 프린트하고

- find_successor(); 함수로 쓰레드이면 그 다음 포인터를 반환, 쓰레드가 아니면 오른쪽 -> 왼쪽 가장 밑으로 간다.

 

 

 

 

 

 

 

 

 

 

6. 완전 이진트리

: 레벨 1부터 k-1까지는 노드가 모두 채워져 있고, k레벨에서는 왼쪽부터 오른쪽으로 노드가 순서대로 채워져 있는 이진 트리이다.

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

 

 

 

 

 

1. 배경

: 주 메모리보다 용량이 큰 기억 공간에 주소 지정이 가능하다.

그렇게 하면 프로그램 일부분만 적재하고 실행시킬 수 있다.

 

-> 프로그래머에게 가상 메모리를 제공하여 이 공간에 주소를 지정한다.

 

 

 

 

 

- 부분 적재의 타당성

: 항상 전체 프로그램이 실행되는 것이 아니다.

 

- 부분 적재의 강점

: 메모리의 크기를 고려하지 않아도 되기 때문에 프로그래밍 작업이 쉬워진다.

: 공간의 제약이 없으므로 중첩이 불필요하다.

 

- 부분 적재의 단점

: 메모리와 디스크 사이의 이동량 증가

: 어느 시기에 어느 페이지를 적재 / 복귀할지 알고리즘이 필요

: 페이지 부재에 대한 처리 방안 요구

 

* 부분 적재 - 운영체제가 관리

* 중첩 - 프로그래머가 직접 설계 및 관리

 

 

 

 

 

 

 

 

2. 요구 페이징

: 페이지가 참조될 때에만, 그 페이지를 메모리에 적재한다.

 

 

 

1) 페이지 부재 오류

: 지정된 프레임 페이지가 메모리에 적재되지 않은 경우

- 페이지가 교체되는 동안 CPU는 다른 프로그램을 실행시킨다.

 

 

 

 

2) 요구 페이지의 성능

- 실제 접근 시간 (EAT)

: (1-p) x 메모리 접근 시간 + p x 페이지 부재 시간 ( p는 페이지 부재율이다. )

 

 

메모리 접근 시간 = 200 nanosecond
페이지 부재 처리 시간 = 8 msec = 8,000,000 nsec

EAT = (1 – p) x 200 + p x (8,000,000) = 200 + 7,999,800 x p (nsec)

10% 성능 감소(지연 시간이 20보다 작으려면?) : 20 > 7,999,800 x p p < 0.0000025

 

- 스왑 공간(메모리 쪽), 디스크 캐시(하드디스크 쪽) 활용

 

 

 

 

 

 

 

 

 

3. 페이지 교체

- 페이지 교체의 필요성 : 메모리에 빈 공간이 없는 경우

페이지 교체 알고리즘

1) 희생자 페이지 선택

2) 희생자 페이지를 디스크에 출력하고, 페이지 테이블에 기록한다.

3) 요구된 페이지를 적재하고, 페이지 테이블 내용을 수정한다.

4) 사용자 프로세스를 다시 시작한다.

 

 

 

- 페이지의 부재와 프레임 개수

: 프레임 수가 증가할수록 페이지 부재 횟수가 감소한다.

 

- 참조 문자열

: 메모리를 참조하는 페이지를 의미한다.

 

 

 

 

 

 

 

 

 

4. 선입선출(FIFO) 교체 알고리즘

: 가장 오래된 페이지가 교체되도록 선택한다.

 

 

 

 

- 문제점 : 벨레디의 변이

: 할당되는 프레임의 수가 증가해도 페이지 부재율이 증가하는 현상

 

 

 

 

 

 

5. 최적 교체 알고리즘

: 앞으로 가장 오래 사용되지 않을 페이지를 교체한다. (미래를 예측)

-> 모든 알고리즘 중에 가장 낮은 페이지 부재율을 보장한다.

 

 

 

 

 

 

 

 

6. LRU(Least Recently Used) 알고리즘

: 가장 오랫동안 사용하지 않은 페이지를 교체한다.

-> 가장 최근에 사용된 것을 기준으로 !

 

 

 

 

 

- LRU의 구현

1) 계수기의 사용

: CPU에 논리 시계나 계수기 추가

 

2) 스택의 사용

 

 

 

 

 

 

 

7. LRU 근접 알고리즘

: LRU의 시간 기록하는 오버헤드를 줄이기 위한 알고리즘이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

 

 

 

진화된 페이지 테이블 구조

: 다중 계층 페이지 테이블

 

 

 

 

1. 2단계 페이징

: 페이지 테이블이 너무 커서 프레임에 안 들어가면 잘라서 저장,
페이지 테이블의 지도를 outer-page table이라고 함

 

 

 

:

 

 

 

 

 

 

 

 

2. 세그먼테이션 기법 (페이징의 변형 버전)

세그먼트 : 메모리의 가변적인 단위이다. 프로그램은 세그먼트들의 집합이다.

세그먼트 기법 : 각각의 크기에 따른 분산 적재

 

 

 

 

 

- 논리 주소는 <세그먼트 번호, 오프셋> 으로 구성

- 세그먼트 테이블 : 가변 크기의 세그먼트 위치 저장

기준(base) : 세그먼트의 시작 물리 주소

한계(limit) : 세그먼트의 길이

 

 

 

 

 

 

 

 

- 할당

: 최상 적합 / 최초 적합 등의 동적 기억 장치 할당 기법 사용한다.

: 외부 단편화 문제 발생

 

 

 

 

 

 

페이징과 세그먼테이션은 공통적으로 프로그램 코드 및 데이터의 공유한다.

 

3. 페이지화된 세그먼테이션

페이징 - 내부 단편화, 세그먼트 - 외부 단편화

페이지화된 세그먼테이션은 외부 단편화 문제 해결 ! but 내부 단편화 발생

 

 

 

 

 

 

 

 

4. 정보처리기사 문제

1) 프로그램을 고정된 크기의 일정한 블록으로 나누는 페이징 기법과 

가변적인 크기의 블록으로 나누는 세그먼테이션 기법이 있다.

 

2) 페이징 기법은 동적 주소 변환 기법을 사용하여 다중 프로그래밍의 효과를 증시킨다.

3) 페이징 기법에서 프로그램을 동일한 크기로 나눈 단위를 페이지라고 하며, 이 페이지를 블록으로 사용하는 기법이다.

4) 페이징 기법은 내부 단편화를 발생시킨다.

5) 페이지 맵 테이블이 필요하다.

6) 세그먼테이션 기법에서는 각 세그먼트는 고유한 이름과 크기를 갖는다.

7) 세그먼테이션 기법에서는 세그먼트 맵 테이블이 필요하다.

8) 20K, 16K, 8K, 40K 빈 기억공간에서 ‘worst fit’을 사용하여
17K의프로그램을 적재할 경우 내부 단편화의 크기는?
-> 23K

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

'Computer Science > Operating System' 카테고리의 다른 글

Practice 5) Thread & Semaphore 1  (0) 2020.12.17
이론 7) 가상 메모리  (0) 2020.12.03
이론 6) 주 메모리 관리 기법 2  (0) 2020.12.02
이론 6) 주 메모리 관리 기법  (0) 2020.12.02
이론 5) 교착 상태 2  (0) 2020.12.02
반응형

 

 

 

 

 

 

 

 

 

1. 메모리 관리 기법 분류

 

1) 연속 메모리 할당 방식

: 프로그램(프로세스)를 적재하는 과정에서 연속적으로 메모리를 할당한다.

: 직접 배치, 중첩(오버레이), 분할 기법이 해당한다.

 

- 고정 분할 기법 : 메모리를 고정된 크기로 분할하여 프로세스에 제공한다. 

- 가변 분할 기법 : 각 프로세스의 크기에 따라 메모리를 분할한다.

 

 

2) 분산 메모리 할당 방식

: 프로세스가 페이지나 세그먼테이션 등의 단위로 보조기억장치에 적재되어 있다가, 프로세스의 요구에 의해 메모리의 여러 영역에 할당된다.

: 현재의 가상 메모리 관리 기법으로 발전하였다. (MMU)

 

 

 

 

2. 연속 메모리 할당

메모리 분할 : 운영 체제 부분과 사용자 부분 둘로 나눈다.

 

 

1) 고정 분할

 

 

 

: 고정된 크기로 분할하기 때문에 논리 주소와 크기가 맞지 않으면 내부에 낭비되는 공간이 생긴다.

이를 "내부 단편화"라고 한다.

 

 

ex) 내부 단편화 예제

(a) 메모리 영역을 10KB, 4KB, 4KB, 4KB 로 나누는 경우

내부 단편화 = 3KB + 1KB = 4KB 이다. 메모리 할당이 되지 않은 영역은 내부 단편화가 아니다.

 

(b) 메모리 영역을 10KB, 8KB, 4KB 로 나누는 경우

내부 단편화 = 4KB + 1KB + 1KB = 6KB 이다. 

 

 

 

 

 

2) 가변 분할

: 고정된 경계를 없애고 각 작업이 필요한 만큼 메모리를 할당한다.

 

: 각 작업이 필요한 메모리만큼 메모리를 할당하기 때문에 해당 작업이 끝났을 때 동일한 크기의 메모리 할당이 필요치 않는다면 낭비되는 공간이 생긴다.

이를 "외부 단편화"라고 한다.

 

 

 

 

- 메모리 적합 기법

: 최초 적합, 최상 적합, 최악 적합

 

1) 최초 적합 기법

: 사용가능공간 리스트에서 충분히 큰 첫 번째 공백 분할 공간에 할당한다.

- 검색은 빠르나 공간 활용도가 떨어진다.

 

 

 

 

 

2) 최상 적합 기법

: 들어갈 수 있는 공간 중 가장 작은 크기의 공간에 할당한다.

- 사용가능공간에 대해 지속적으로 정렬해야 하므로 비효율적이다.

- 공간 활용도는 향상되나, 할당되는 과정에서 많은 시간이 소요된다.

 

 

 

3) 최악 적합 기법

: 작업을 가장 큰 사용가능공간에 할당한다. 

: 공간이 크기순으로 정렬되지 않았다면 전 리스트를 검색한다.

 

 

 

 

 

 

3. 단편화를 해결할 방법

 

1) 압축 (외부단편화 해결)

: 메모리의 여러 영역들을 옮겨 모든 작은 빈 공간들을 연속된 하나의 큰 빈 공간으로 만드는 작업이다.

: 재배치가 실행시간에 동적으로 이루어지는 경우에만 가능하다.

 

단점

- 압축할 동안 시스템은 모든 일을 정지한다.

- 재배치 정보를 관리할 필요가 있다.

 

 

 

 

 

 

2) 버디 시스템

: 요청된 크기가 버퍼보다 작으면 버퍼를 동일한 크기의 2개 버디로 나눈다.

: 가능할 때마다 인접한 자유로운 버퍼들을 합치는 과정을 반복한다.

+ 2의 배수로 설정한다.

 

 

ex) 7K, 6K, 3K 프로세스 할당

 

 

 

 

 

 

 

 

 

 

4. 분산 메모리 할당

 

1) 페이징 기법

: 프로그램을 페이지라는 고정 크기 단위로 나누어 분산 적재한다.

 

 

 

 

 

 

 

2) 페이징 시스템 하드웨어

: 논리 페이지에 물리 메모리(페이지) 프레임을 적재하는 과정을 수행하는 페이지 시스템 하드웨어 구조이다.

 

논리 주소 = 페이지 번호(p) + 페이지 변위(d)

p에 저장된 f값은 물리 메모리 페이지 번호이다.

페이지 변위란, 테이블의 자리 번호이다.

 

물리 주소 = 메인 메모리의 프레임 번호(f) + 페이지 변위(d)

f는 실제 메모리의 페이지 기준 주소로 메인 메모리의 프레임 번호이다.

 

 

 

 

페이징 시스템의 물리적 주소 변환의 예)

 

 

 

 

 

 

 

3) 페이징 스케줄링

: 새로운 프로세스를 페이지 단위로 표현하고 순서대로 사용가능한 프레임 리스트에 할당한다.

 

 

 

- 페이지 크기

: 페이지 크기는 하드웨어에 따라 결정된다.

: 일반적으로 2의 제곱, 512bytes ~ 16Kbytes

단순한 내부 단편화만 생각하면 페이지 크기가 작은 것이 바람직하다.

다만, 페이지 크기가 작을수록 페이지 테이블 유지 부담이 커지기 때문에 적절한 페이지 크기를 산정해야 한다.

 

 

 

 

 

 

 

 

 

 

 

5. 페이지 테이블의 구현

1) 전용 레지스터의 집합

: 페이지 테이블이 cpu에 위치한다. 

- 페이지 테이블이 작은 경우에만 가능하다.

 

2) 주기억 장치에 유지

: CPU 내의 테이블 기준 레지스터(PTBR) 에 저장한다.

- 기억 장치 위치에 접근하는 데 많은 시간이 소요된다. ( 두 번의 기억장치 접근 필요 )

 

 

 

 

 

 

3) 변환 우선참조 버퍼 TLB 사용

: 페이지 테이블을 캐시에 저장한다.

- 탐색은 빠르지만, 하드웨어가 고가이다.

 

-> 주기억 장치에 유지하는 것처럼 기억 장치 위치에 접근하는 데 많은 시간이 소요되지는 않는다.

다만, 연관사상표에 일치하는 항목이 없을 때, 더 시간이 많이 걸리기 때문에 이 점을 감안해야 한다.

 

 

 

* 적중률 및 실제 접근 시간 *

- 연관 레지스터(캐시) 탐색 시 50ns, 메모리에 접근 시 750ns

IF 연관 레지스터에 있는 경우 : 50 + 750 = 800ns

IF 연관 레지스터에 없는 경우 : 50 + 750 + 750 = 1550ns

 

- 적중률 80%인 경우, 실제 접근 시간 = 800 * 0.8 + 1550 * (1-0.8) = 950ns

- 적중률 90%인 경우, 실제 접근 시간 = 800 * 0.9 + 1550 * (1-0.8) = 875ns

 

 

 

 

 

 

 

6. 페이지 보호 및 공유

: 페이지 단위로 판독 전용, 판독/기록 전용, 실행 전용 등의 보호를 지정한다.

 

 

 

- 공유 페이지

( 분산 메모리 관리의 장점 )

: 시분할 환경에서 중요한 공통된 코드들을 프로세스 사이에서 공유할 수 있다.

: 비슷한 프로세스끼리 논리 주소 공간에서 같은 위치에 놓을 수 있기 때문이다.

 

 

 

 

 

 

 

7. 페이징 기법의 장단점

장점

- 공유 페이지를 이용한다.

- 외부 단편화를 제거할 수 있다. ( 끼워 넣으면 되니까 )

- 외부 단편화가 없기 때문에 압축 기능이 필요없다. 

 

단점 

- 페이징 사상을 위한 하드웨어 준비로 인한 가격 상승

- 속도 저하 -> 캐시 사용으로 속도 향상 가능하다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

'Computer Science > Operating System' 카테고리의 다른 글

이론 7) 가상 메모리  (0) 2020.12.03
이론 6) 주 메모리 관리 기법 3  (0) 2020.12.02
이론 6) 주 메모리 관리 기법  (0) 2020.12.02
이론 5) 교착 상태 2  (0) 2020.12.02
이론 5) 교착 상태  (0) 2020.12.02
반응형

 

 

 

 

1. 배경

: 다중 프로그래밍에서 주기억 장치를 여러 프로그램에 공유하려면 주기억 장치 관리 기법이 필요하다.

 

 

2. 주소 바인딩

: 프로그램의 명령어와 데이터를 기억 장치 주소 공간으로 할당하는 것을 의미한다.

 

1) 컴파일 시간 바인딩

: 프로그램의 메모리 저장 위치가 고정된다.

 

2) 적재 시간 바인딩

: 프로그램이 메모리에 적재되는 시기에 메모리 위치가 결정된다. 재배치가 가능하다.

 

3) 실행 시간 바인딩

: 실행 중간에 메모리 저장 위치가 MMU에 의해서 결정되며, 실행중에 위치 변경이 가능하다.

-> 연속 메모리 할당 방식 / 분산 메모리 할당 방식이 있다.

 

,

 

 

 

 

 

 

4) 논리 주소

: CPU가 생성하는 주소

 

5) 물리 주소

: 기억 장치에 나타나는 주소

-> 아래 그림에서 메모리(주기억장치)와 하드디스크(보조기억장치) 를 의미한다.

 

 

 

 

 

- 컴파일 시간 바인딩과 적재 시간 바인딩 : 논리 주소와 물리 주소가 같다.

- 실행 시간 바인딩 : 논리 주소와 물리 주소가 다르다.(MMU가 변경시킨다.)

 

 

 

 

 

 

3. 기억 장치 관리기(MMU)

: 논리 주소(가상 주소)의 물리 주소 사상을 수행하는 하드웨어이다.

: 재배치 레지스터를 사용한다.

 

 

 

 

 

 

 

 

4. 중첩( Overlays ) 

: 허용된 메모리 크기보다 큰 프로그램을 실행할 때 해결법이다.

 

- 오버레이 영역은?

: 필요에 따라서 프로그램을 적재하여 실행하고, 필요없게 되면 다른 프로그램으로 교체되는 부분이다.

: 프로그래머가 오버레이 구조를 설계하고 프로그램해야 한다.

 

 

 

 

 

 

 

 

5. 교체 (Swapping)

: 할당 시간량이 소진되거나 높은 우선 순위 프로세스가 도착할 때, 한 프로세스를 디스크로 보내고 새 프로세스를 불러들인다.

 

 

- 메모리가 큰 컴퓨터는 스와핑이 적어 성능이 좋다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

'Computer Science > Operating System' 카테고리의 다른 글

이론 6) 주 메모리 관리 기법 3  (0) 2020.12.02
이론 6) 주 메모리 관리 기법 2  (0) 2020.12.02
이론 5) 교착 상태 2  (0) 2020.12.02
이론 5) 교착 상태  (0) 2020.12.02
이론 0) 운영체제 기본  (0) 2020.10.22
반응형

 

 

 

 

 

 

 

 

 

1. 은행가 알고리즘 (Banker's Algorithm)

: 교착상태 회피 알고리즘 + 자원의 종류가 여러 개 일 때

 

 

 

1) 안전성 알고리즘

: 안정상태인지 불안정상태인지 검사

 

ex) 3개 종류의 자원(A, B, C)

 

 

 

 

 

현재사용량 : Allocation
시작잔여량 : Available

p1, p3 종료가능, 아무거나 선택
p1 종료 후 잔여 : 3 3 2 + 2 0 0 = 5 3 2
p3 종료 후 잔여 : 5 3 2 + 2 1 1 = 7 4 3

안정 순열 < p1, p3, p4, p0, p1 > 등 

 

 

 

 

 

2) 자원 요청 알고리즘

 

① Request1 <= Available ((1, 0, 2) <= (3, 3, 2)) 확인

② 새로운 시스템 상태가 안정한지 판별하기 위해 안정성 알고리즘 실행

③ <P1, P3, P4, P2, P0> 순서의 안정 순열 존재

④ 프로세스 P1의 요청을 허락

 

ex)

이 상태에서 Request1 = (1, 0, 2)이면? (P1이 A자원 +1과 C자원 +2를 더 요구한다면?)

 

 

 

 

주의 !

Need 에서 요청한만큼 빼줘야함

 

 

 

 

 

 

 

 

3) 은행원 알고리즘의 단점

 

- 할당할 수 있는 자원의 일정량을 요구한다.

- 사용자 프로세스 수가 일정해야 한다.

- 사용자가 최대 필요량을 미리 알려주도록 요구된다.

- 교착상태 회피 알고리즘을 사용하면 계속해서 상태를 파악하고 그에 따라 대응해야 하기 때문에 시스템 과부하가 증가한다.

- 항상 불안정 상태를 방지해야 하므로 자원 이용도가 낮다.

 

 

 

 

 

 

 

 

 

 

2. 교착 상태 탐지

 

: 교착 상태가 발생하도록 허용한다.

: 교착 상태가 발생했는지 탐지 알고리즘

: 교착 상태로부터 회복하는 알고리즘 제공한다.

 

-> 은행가 알고리즘에서 조금 변형한 것이다.

 

 

1) 은행가 알고리즘과의 차이

: 은행가 알고리즘에서는 Request를 받아줄지 말지를 고민하는 상태였다면

교착 상태 탐지 알고리즘에서는 이미 Request 가 요구를 하고있다. 모든 프로세스가 대기하는 상태이므로 Available은 남아있지 않다. 

 

 

<P0, P2, P3, P1, P4> 로 안정 순열이 존재한다.

 

 

만약 P2가 C자원 하나를 더 요구한다면?

 

P0 다음에 할당할 수 있는 프로세스가 없으므로 교착 상태에 놓이게 된다.

 

 

 

 

2) 교착 상태 탐지 알고리즘의 특징

- 교착 상태가 자주 발생하면 탐지 알고리즘도 자주 호출된다.

- 요청할 때마다 연산 시간 부담이 크다.

- 경제적인 방법은 호출 빈도를 줄이는 것으로, 한 시간마다 또는 CPU 이용률이 40% 이하로 저하될 때마다 호출하는 방법이 있다.

( CPU 이용률이 낮다는 것은 교착 상태로 인해 문제가 생겼을 가능성이 높기 때문이다. )

 

 

 

3) 교착 상태 회복

- 모든 교착 상태 프로세스들을 중지시키거나, 

교착 상태 사이클이 제거될 때까지 하나씩 프로세스를 중지시키는 방법이 있다.

 

 

 

 

 

 

3. 교착 상태를 다루는 결합된 방법

: 3가지 방법(예방, 회피, 탐지)를 결합하여 시스템 자원 종류에 따라 최적의 방법을 고안한다.

 

 

 

4. 정보처리기사 문제 풀어보기

 

1) 은행가 알고리즘은 교착 상태 회피 알고리즘이다

2) 교착상태 4가지 조건 중 어느 하나를 제거하는 방법은 교착 상태 예방 알고리즘이다.

3) 교착 상태 회피 알고리즘은 

사전에 시스템을 제어하여 교착 상태를 회피하는 알고리즘이다.

대표적인 예로 은행가 알고리즘이 있다.

교착상태가 발생할 확률을 완전히 배제한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

+ Recent posts