Swap memory(스왑 메모리)

- 실제 메모의 물리적인 메모리(RAM)이 가득 찬 경우, 운영체제가 사용하는 가상 메모리의 일부

- 운영체제에서 사용 가능한 메모리 보다 더 많은 메모리가 필요한 경우, 데이터 저장을 위한 버퍼 역할

 

 

 

Swapping

- 컴퓨터와 실제 메모리와 가상 메모리 간의 정보 교환이 이루어지는 것

- 현재 메모리에서 다른 저장공간(HDD or SSD)으로 옮겨진 후, 다시 돌아오는 식으로 메모리 교체가 이루어질 수 있다.

- swap-out : 메모리 공간에서 원하는 페이지를 디스크에서 내보내는 방법

- swap-in : 디스크에 있던 페이지를 메모리에 다시 read 하는 과정

 

 

성능 이슈

- 빈번한 Swapping은 디스크 I/O를 발생시키기 때문에 시스템 성능 저하가 일어날 수 있기 때문에 최대한 메모리 부족 상황을 방지하기

 

 

활용 예시

- Hibernation(최대 절전 모드) : 스왑 메모리는 현재 실행 중인 시스템 상태를 디스크에 저장하고 나중에 다시 불러올 수 있다.

- 해당 머신에서 실행해야 하는 애플리케이션이 더 많은 메모리를 요구할 때 스왑 메모리를 활용한다.

- 갑작스런 메모리 사용량을 RAM 대신 스왑 메모리로 완화할 수 있다. 

 

'CS > 운영체제' 카테고리의 다른 글

[운영체제] 운영체제 요약 정리  (0) 2023.07.09
[운영체제] 운영체제란?(Operating System, OS)  (0) 2022.07.04

1. 컨테이너 기술이란?
- 모놀리스 애플리케이션에서 MSA 으로 독립적 배포가 가능해지면서 발생한 관리 및 종속성 문제 해결
- 격리된 실행 환경 제공, 호스트 OS 에서 독립된 프로세스로 실행되어 자원 소비 및 오버헤드 최소화

 


2. 도커란?
- 컨테이너 기술을 사용해서 애플리케이션을 패키징, 배포, 실행하기 위한 오픈 소스 플랫폼
- 도커 파일로 이미지를 빌드하고, 이미지로 컨테이너를 실행한다.

 


3. 도커 파일, 도커 이미지, 도커 컨테이너의 개념은 무엇이고, 서로 어떤 관계입니까?
- 도커 파일(Dockerfile)
    - 도커에서 이미지를 생성하기 위해 작성하는 파일.
    - 컨테이너 설정을 정의한 것
- 도커 이미지(Docker Image)
    - 실행 가능한 컨테이너의 빌드된 상태
    - 애플리케이션을 실행하기 위한 모든 환경을 포함한다.
- 도커 컨테이너(Docker Container)
    - 도커 기반 컨테이너 이미지에서 생성된 리눅스 컨테이너
    - 실행 중인 컨테이너는 도커를 실행하는 호스트에서 실행되는 프로세스
    - 호스트와 호스트에서 실행 중인 다른 프로세스와 격리되어 있다.

신장 트리(Spanning Tree)

- 하나의 그래프가 있을 때, 모든 노드를 포함하면서 사이클이 존재하지 않는 그래프

 

신장 트리의 특징

1. 모든 노드를 포함

2. 사이클이 없음

3. 연결성 유지 : 그래프의 모든 노드를 연결


최소 신장 트리 (MST, Minimum Spanning Tree)

- 신장 트리에서 가중치의 합이 최소가 되는 신장 트리

- 알고리즘 종류 : 프림 알고리즘, 크루스칼 알고리즘

 

 

프림 알고리즘(Prim's Alogrithm)

- 시작 노드를 선택한다.

- 해당 노드와 가장 작은 가중치의 간선을 선택한다.

- 새로운 노드를 트리에 추가한다.

- 선택한 노드의 집합을 확장하면서 최소 신장 트리를 형성한다.

 

- 간선의 수가 적을 때 적합하다.

- Priority Queue 우선순위 큐 사용

- 시간 복잡도 : O(E log E) // E는 간선의 수

 

 

크루스칼 알고리즘(Kruskal's Alogrithm)

- 그래프의 간선을 가중치의 오름차순으로 정렬하고, 가장 작은 가중치부터 선택해서 최소 신장 트리를 구성한다.

- 사이클을 형성하지 않는 간선을 선택하면서 트리를 확장한다.

- 유니온 파인드(Union Find) 자료구조 사용으로, 사이클 여부 확인

 

- 그리디 알고리즘 사용

- 간선의 수가 많을 때 적합하다.

- 시간 복잡도 : O(E log V) // V는 노드의 수


[최소 신장 트리 알고리즘 예제]

백준 1414번

https://www.acmicpc.net/problem/1414

 

1414번: 불우이웃돕기

첫째 줄에 컴퓨터의 개수 N이 주어진다. 둘째 줄부터 랜선의 길이가 주어진다. i번째 줄의 j번째 문자가 0인 경우는 컴퓨터 i와 컴퓨터 j를 연결하는 랜선이 없음을 의미한다. 그 외의 경우는 랜선

www.acmicpc.net

- N 개의 컴퓨터가 서로 연결되어 있는 랜선 길이가 주어질 때

- 모든 컴퓨터가 서로 연결되도록 만들고, 랜선 길이가 최대 값이 되는 값을 출력

 

 

- 파이썬 코드

def find(parent, x):  # 특정 원소가 속한 집합 찾기
    if parent[x] != x:  # 루트 노드가 아니면, 루트 노드 찾을 때까지 재귀
        return find(parent, parent[x])
    return parent[x]


def union(parent, a, b):  # 두 원소가 속한 집합 합치기
    a = find(parent, a)
    b = find(parent, b)
    if a < b:  # 더 작은 번호가 부모 노드
        parent[b] = a
    else:
        parent[a] = b


n = int(input())  # 컴퓨터 개수
edges = []
result = 0
parent = [i for i in range(n + 1)]  # 부모 테이블 초기화

for i in range(n):
    s = input()

    for j in range(len(s)):
        cost = 0  # 0이면 그대로
        ch = s[j]
        if ch.islower():  # 소문자
            cost = ord(ch) - ord('a') + 1
        elif ch.isupper():
            cost = ord(ch) - ord('A') + 27
        edges.append((cost, i + 1, j + 1))
        result += cost  # 모든 비용 계산

edges.sort()  # cost 오름차순 정렬

for cost, a, b in edges:
    if cost == 0:
        continue
    if find(parent, a) != find(parent, b):  # 사이클 발생 하지 않는 경우에 MST 포함
        union(parent, a, b)
        # print(cost)
        result -= cost

flag = True
for i in range(1, n + 1):
    if find(parent, i) != 1:
        flag = False

if flag:
    print(result)
else:
    print(-1)

백준 10423번

https://www.acmicpc.net/problem/10423

 

10423번: 전기가 부족해

첫째 줄에는 도시의 개수 N(1 ≤ N ≤ 1,000)과 설치 가능한 케이블의 수 M(1 ≤ M ≤ 100,000)개, 발전소의 개수 K(1 ≤ K ≤ N)개가 주어진다. 둘째 줄에는 발전소가 설치된 도시의 번호가 주어진다. 셋째

www.acmicpc.net

- 도시의 개수 N

- 설치 가능한 케이블 수 M

- 발전소 개수 K

- 모든 도시에 전기를 공급할 수 있도록 연결되어 있고, 케이블 설치 최소 비용 구하기

- 발전소가 설치된 도시는 연결하지 않아도 된다.

 

 

- 파이썬 코드

def find(parent, x):
    if parent[x] != x:
        return find(parent, parent[x])
    return parent[x]


def union(parent, a, b):
    a = find(parent, a)
    b = find(parent, b)
    if a < b:
        parent[b] = a
    else:
        parent[a] = b


n, m, k = map(int, input().split())  # 도시 개수, 케이블 수, 발전소 개수
numbers = list(map(int, input().split()))  # 발전소 설치된 도시 번호
parent = [i for i in range(n + 1)]
edges = []
answer = 0

for num in numbers:  # 발전소 설치된 도시의 루트를 0 으로 초기화
    parent[num] = 0

for _ in range(m):
    u, v, w = map(int, input().split())  # u 도시와 v 도시 연결 비용 w
    edges.append((w, u, v))

edges.sort()

for cost, a, b in edges:
    if find(parent, a) != find(parent, b):  # 사이클이 아닌 경우에만 계산
        union(parent, a, b)
        answer += cost

print(answer)

7장 분산 시스템을 위한 유일 ID 생성기 설계

1단계 문제 이해 및 설계 범위 확정

  • ID 특성
    • 유일성, 정렬 가능
  • 새로운 레코드의 ID의 증가 값
    • 증가 값이 1씩 증가하지는 않지만, 과거의 값보다 나중에 만든 값이 더 큰 ID를 갖는다.
  • ID는 숫자로 구성
  • 시스템 규모

2단계 개략적 설계안 제시 및 동의 구하기

  • 분산 시스템에서 유일성이 보장되는 ID 생성 방법
    • 다중 마스터 복제(multi-master replication)
    • UUID(Universally Unique Identifier)
    • 티켓 서버(ticket server)
    • 트위터 스노플레이크(twitter snowflake) 접근법

  • 다중 마스터 복제

  • 데이터 베이스의 auto_increment 기능을 활용한다.
  • 증가 값은 k만큼 증가
  • k = 현재 사용 중인 데이터베이스 서버 수
  • 단점
    • 여러 데이터 센터에 걸쳐 규모를 확장하기는 어렵다.
    • ID 유일성은 보장되지만, 시간 흐름에 맞추어 커지도록 하기에는 힘들다.
    • 서버 추가나 삭제할 때에도 잘 동작하기 힘들다.

  • UUID

  • 컴퓨터 시스템에 저장되는 정보를 유일하게 식별하기 위한 128비트 수
  • 서버 간 조율 없이 독립적으로 생성 가능
  • 각 웹 서버는 별도 ID 생성기로 독립적인 ID 생성이 가능하다.
  • 장점
    • UUID 만드는 것이 간단하고, 동기화 이슈도 없다.
    • 규모 확장이 간단하다.
  • 단점
    • ID가 128비트이기 때문에 길다.
    • ID 시간순 정렬이 어렵다.
    • ID에 숫자가 아닌 값이 포함된다.

  • 티켓 서버

  • auto_increment 기능을 갖춘 데이터베이스 서버(티켓 서버)를 중앙 집중형으로 하나만 사용한다.
  • 장점
    • 유일성이 보장되는 숫자 ID를 간단하게 만들 수 있다.
    • 규모가 적은 애플리케이션에 적합
  • 단점
    • 티켓 서버가 SPOF(Single-Point-of-Failure)
    • 장애가 발생하면, 해당 서버를 사용하는 모든 시스템에 영향을 끼친다.

  • 트위터 스노플레이크 접근법

  • ID를 바로 생성하기 전에, divide and conquer 적용
  • sign : 음수, 양수 구분
  • timestamp : 기원 시각(epoch) 이후로 몇 밀리초가 경과했는지 나타내는 값
  • 데이터센터 ID
  • 서버 ID
  • 일련번호 : 각 서버에서 ID 생성할 때마다 일련 번호를 1씩 증가

📌 대규모 시스템 설계 기초

13장 : 검색어 자동 완성 시스템

  • 검색어를 입력하고 있을 때, 자동으로 완성되는 검색어 만들기
  • 검색어 자동완성(autocomplete, typeahead, search-as-you-type, incremental search)
  • 예제) 검색창에 단어를 입력했을 때 자동완성 되는 검색어들


1단계 문제 이해 및 설계 범위 확정

  • 요구사항 파악하기
    • 자동완성 검색어는 첫 부분인지, 중간 부분인지
    • 몇 개의 검색어를 표시
    • 검색어를 고르는 기준 : 인기순, 최신순
    • 맞춤법 검사 기능을 제공
    • 다국어 지원
    • 대문자, 소문자, 특수 문자 처리 여부
    • 사용자의 수는?
  • 요구사항 정리하기
    • 빠른 응답 속도
    • 검색어의 연관성
    • 정렬 : 계산 결과는 인기도 등의 순위 모델을 사용해야 한다.
    • 규모 확장성 : 트래픽을 감당할 수 있도록 확장 가능해야 한다.
    • 고가용성 : 일부에 장애가 발생하더도, 시스템은 계속 실행되어야 한다.
  • 개략적 규모 추정
    • 일간 사용자 천 만명 가정
    • 한 사용자는 평균적으로 일일 10건 검색
    • 평균적으로 20바이트의 데이터를 입력한다고 가정
      • 문자 인코딩 방법은 ASCII를 사용하면 1문자 = 1바이트
      • 평균적으로 질의문은 4개의 단어로 이루어져 있다.
      • 각 단어는 평균적으로 다섯 글자로 구성
      • 결과 = 질의당 평균 4 X 5 = 20 바이트
    • 검색 창에 글자를 입력하면, 클라이언트는 백엔드에 요청을 보낸다.
    • 평균적으로 1회 검색당 20건의 요청이 백엔드에 전달
    • 계산 = 1000만 사용자 X 10 질의 / 일 X 20자 / 24시간 / 3600초)
    • 초당 24000건의 QPS
    • 질의 중에 20%가 신규 검색어라면, 1000만 사용자 X 10질의 / 일 X 20자 X 20%
    • 0.4GB의 신규 데이터가 시스템에 추가된다.

2단계 개략적 설계안 제시 및 동의 구하기

  • 시스템 구성 정리
  1. 데이터 수집 서비스(data gathering service)
  2. 질의 서비스(query service)

데이터 수집 서비스

  • 사용자가 입력한 질의를 실시간으로 수집하는 서비스
  • 데이터가 많은 애플리케이션에서는 어려운 작업
  • 질의문과 사용빈도를 저장하는 빈도 테이블(frequency table)이 있다고 가정

질의 서비스

  • 주어진 질의에 다섯 개의 인기 검색어를 정렬하는 서비스
  • 주어진 빈도 테이블
    • query : 질의문을 저장하는 필드
    • frequency : 질의문이 사용된 빈도를 저장하는 필드

  • 사용자가 "tw" 를 검색하게 되면, 아래와 같이 자동 완성 검색표가 완성 되어야 한다.
검색어 : tw
twitter
twitch
twilight
twin peak
twitch peak

 

  • 질의문 SQL
SELECT * FROM frequency_table
WHERE query Like `prefix%`
ORDER BY frequency DESC
LIMIT 5

 

  • 하지만 위와 같이 설계한다면, 데이터가 많아질 때 데이터베이스의 병목 현상이 일어날 수 있다.

3단계 상세 설계

  • 트라이(trie) 자료구조
  • 데이터 수집 서비스
  • 질의 서비스
  • 규모 확장이 가능한 저장소
  • 트라이 연산

트라이 자료구조

  • 관게형 데이터베이스를 사용할 때 가장 인기 있는 다섯 개의 질의문을 골라내는 방법은 효율적 X
  • 트라이 자료구조로 해결
  • 트라이
    • 문자열들을 간략하게 저장할 수 있는 자료구조
    • 트리 형태의 자료구조
    • 루트 노드는 빈 문자열
    • 각 노드는 하나의 문자만 저장한다.
  • tree, try, true, toy, wish, win 질의어를 트라이에 보관할 때

  • 빈도를 따라 정렬해야 하기 때문에, 빈도 정보를 저장할 빈도 테이블

  • 빈도 테이블을 트라이 노드에 저장하게 되면

  • 질의어 찾는 방법
    • p(접두어 길이), n(트라이 노드 개수), c(주어진 노드의 자식 노드 개수)
      • 해당 접두어를 표현하는 노드를 찾기 -> O(p)
      • 해당 노드부터 시작하는 하위 트리를 탐색해서, 모든 유효 노드를 찾는다. -> O(c)
      • 유효 노드를 정렬해서 가장 인기 있는 k개를 찾는다. -> O(clogc)
  • 예시 : k = 2, 질의어 'be'
    • 접두어 노드 'be' 찾기
    • 해당 노드의 하위 트리들을 탐색해서 모든 유효 노드를 찾는다.
    • 유효 노드를 정렬해서 2개만 고른다.

  • 최악의 경우에는 전체 트라이를 검색해야 하는 문제 발생
    • 해결 방법
      • 접두어 최대 길이 제한 두기
      • 각 노드에 인기 검색어를 캐시


데이터 수집 서비스

  • 계속 대용량의 데이터를 트라이에 갱신하면 성능 저하
  • 인기 검색어는 자주 바뀌지 않을 것이기 때문에 자주 갱신할 필요가 없다.
  • ex. 트위터는 검색어를 자주 갱신해주어야 하지만, 구글 같은 경우 자주 바꿔줄 필요 X

  • 데이터 분석 서비스 로그 : 검색창에 입력된 질의에 대한 원본 데이터

  • 로그 취합 서버 : 제각각인 데이터 형식들을 잘 집계(aggregation) 해서 쉽게 소비할 수 있도록 한다.
    • 트위터 같이 결과를 빨리 보여줘야 하면 데이터 취합 주기를 짧게, 대부분의 경우 일주일에 한 번 정도 로그를 취합해도 된다.
  • 취합된 데이터 : time, frequency 필드를 통해 해당 쿼리에 대한 시작한 날짜, 해당 주에 사용된 횟수의 합을 저장한다.
  • 작업 서버 : 주기적으로 비동기적 작업을 실행하는 서버 집합
    • 트라이 자료구조를 만들고, 트라이 데이터베이스에 저장하는 역할
  • 트라이 캐시 : 분사 산 캐시 시스템으로, 트라이 데이터를 메모리에 유지하여 읽기 연산 성능을 높인다. 매주 갱신하도록 한다.
  • 트라이 데이터베이스 : 지속성 저장소. 문서 저장소 or 키 값 저장소 형태로 사용
    • 문서 저장소(document store)
      • 새 트라이를 매주 만들어야 해서, 주기적으로 트라이를 직렬화하여 DB에 저장
      • MongoDB 같은 문서 저장소 활용
    • 키 값 저장소
      • 해시 테이블 형태로 변환
        • 트라이에 보관된 모든 접두어를 해시 테이블 키로 변환
        • 각 트라이 노드에 보관된 모든 데이터를 해시 테이블 값으로 변환


질의 서비스

  • 비효율성 개선 설계
  1. 검색 질의가 로드 밸런서로 전송
  2. 로브 댈런서가 해당 질의를 API 서버에 전송
  3. API 서버는 트라이 캐시에서 데이터를 가져와 해당 요청에 대한 자동완성 검색어 제안 응답 구성
  4. 데이터가 트라이 캐시에 없는 경우의 데이터는 데이터베이스에서 가져와서 캐시에 채운다.


트라이 연산

  • 트라이 생성 : 작업 서버 담당. 데이터 분석 서비스의 로그나 데이터베이스로부터 취합된 데이터를 이용
  • 트라이 갱신
    • 매주 한 번 갱신해서 기존 트라이를 대신 하는 방법
    • 각 노드를 개별적으로 갱신하는 방법 -> 트라이가 적을 때만 좋다.
      • 트라이 노드를 갱신할 때 그 위의 상위 노드도 갱신해야 하기 때문

  • 검색어 삭제
    • 폭력적인 질의어는 자동완성에서 제거한다.
    • 트라이 캐시 앞에 필터 계층(Filter layer)을 두고 부적절한 질의어가 반환되지 않도록 한다.
    • 검색어를 물리적으로 삭제하는 것은 다음 업데이트에 비동기적으로 진행


저장소 규모 확장

  • 서비스 크기가 확장될 때 규모를 확장할 수 있도록 해결한다.
  • 첫 글자 기준으로 샤딩(sharding) 해보기
    • 영어는 26개의 알파벳으로 이루어져 있다.
    • 서버 2개인 경우, a부터 m까지 첫 번째 서버, 나머지 두 번째 서버
    • 서버 3개인 경우, a부터 i까지 첫 번째 서버, ...
  • 다른 방법으로는 샤딩을 계측적으로
    • 첫 번째 샤딩에 첫 번째 글자
    • 두 번째 샤딩에 두 번째 글자
  • 하지만 데이터가 균등하지 않게 분배되는 문제가 생길 수 있따.
  • ex. c로 시작하는 단어가 x로 시작하는 단어보다 많은 경우
  • 검색어 대응 샤드 관리자(shard map manager)로 어떤 검색어가 어느 저장소 서버에 저장되는지에 대한 정보를 관리한다.


4단계 마무리

  • 다국어 지원을 하려면?
    • 트라이에 유니코드(Unicode) 데이터를 저장해야 한다.
    • 유니코드 : 모든 문자 체계를 지원하는 표준 인코딩 시스템
  • 국가별로 인기 검색어 순위가 다르면?
    • 국가별로 다른 트라이를 사용
    • 트라이를 CDN에 저장해서 응답속도 개선
  • 실시간으로 변하는 검색어 추이를 반영하려면?
    • 스트림 프로세싱에 필요한 시스템
    • 하둡 맵리듀스, 스파크, 카프카 등이 필요하다.

📌GitHub Actions 실습

CI/CD 란?

  • CI : Continuous Integration
    • 지속적인 통합
    • 코드, 빌드, 테스트 부분을 자동화해서
    • 커밋할 때마다 빌드와 자동 테스트로 동작을 확인해서 문제가 생기지 않도록 보장한다.
    • 개발에 더 많은 시간을 투자 가능
  • CD : Continuous Delivery / Deployment
    • 지속적인 제공, 배포
    • 배포 자동화 과정
    • CI 프로세스를 통과하면 마지막에 배포하는 과정

GitHub Actions

  • Workflow
  • Job
  • Step
  • Action

yaml 파일 예시

name: 'Workflows name'

on: push // on은 script 가 언제 돌아가야하는지에 대한 부분 -> push 가 들어갈 때마다 실행된다.

jobs: // 스크립트가 해야하는 행동
  first-job: // job의 이름이고, 정해진 규칙은 없다.
    name: 'First Job' // name에 지정한 것은 각각 안에서 여러가지 나뉘는데 각각 job에 대한 이름 설정 안하면 위에 셋팅한 이름으로 default

    runs-on: ubuntu-latest // 어느 가상 환경에 올릴 것인지 보통 3가지 - windows mac linux

    steps:
      - name: Say Hello World 1
        shell: bash
        run: |
          echo "Hello World from step 1"

      - name: Say Hello World 2
        shell: pwsh
        run: |
          echo "Hello World from step 2"

 

  • GitHub Actions 관련 문서 링크

https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows


 

GitHub Action 요구사항 해결 방안

  • OS 종류와 Node 버전이 다양한 경우

-> 매트릭스 빌드 사용

  • 빌드할 때마다 테스트 실행이 불편한 경우

-> 템플릿 변경으로 빌드 테스트 분리

  • 다른 job에서 빌드 아티팩트 접근이 안되는 경우

-> Built-in 스토리지 이용


매트릭스 빌드

  • 각 경우의 수에 맞게 빌드 아티팩트를 만들어서 실행
...
  strategy:
    matrix:
      os: [ubuntu-latest, windows-2016]
      node-version: [12.x, 14.x]
...
  • 우분투 12, 14버전
  • 윈도우 12, 14버전 실행

빌드, 테스트 분리

  • build를 build와 test로 분리
jobs:
  build:
    - run: npm ci
    - run: npm run build --if-present
    - run: npm test
jobs:
  build:
  ...
  test:
  ...

 


job 병렬 실행 -> 종속적으로 실행 시키기

jobs:
  build:
    ...
  test:
    needs: build // 이 부분이 실행되기 위해서는 build job이 필요
    ...

 


GitHub Actions 요구 사항 해결 방안

  • main 브랜치 에러 위험

-> 브랜치 정책 설정

  • Pull Request 는 언제 merge?

-> PR 리뷰 강제화

  • 늘어나는 Issue 와 PR 관리의 어려움

-> Custom action 으로 라벨링


Branch 정책 설정 방법

  • Repo 의 Settings
  • Branches 메뉴에서
  • Branch protection rules 에 있는 Add rule

 

 

 

 

  • Require pull request reviews before merging
    • 브랜치를 다른 브랜치와 merge 하려고할 때, PR 요청을 통해서 리뷰되어야만 가능
  • Require status checks to pass before merging
    • merge 전에 status check 를 통과해야 한다.

실습

  • Comment 에 "/close" 커맨드 입력 시 이슈 닫는 워크플로우 작성
name: 'Close Issue Condition Workflows'

on:
  issue_comment: 
    types: [ created ]

jobs: 
  close-issue:
    name: 'Close Issue Job' 
    if: contains(github.event.comment.body, '/close')
    runs-on: ubuntu-latest

    steps:
    - name: Closed Issue
      uses: actions/github-script@v6
      with:
        script: |
          github.rest.issues.update({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            state: 'closed'
          })

 

 

 

 

 

📌 운영체제

  • 실행할 프로그램에 필요한 자원을 할당하고
  • 프로그램이 올바르게 실행되도록 돕는 프로그램
  • 동시다발적으로 생성, 실행, 삭제되는 다양한 프로세스를 관리한다.
    • 프로세스, 스레드, 프로세스 동기화, 교착 상태 해결
  • 자원 접근 및 할당
    • CPU(CPU 스케줄링), 메모리(페이징, 스와핑), 입출력장치

메모리 구조

  • 커널 영역(Kernel)
    • 운영체제의 핵심 영역
    • 커널 : 운영체제의 핵심 서비스를 담당하는 부분
    • 응용 프로그램이 자원에 접근하려면 운영체제에 도움을 요청(운영체제의 코드를 실행)해야 한다. -> 이중 모드로 구현
    • 시스템의 모든 것을 통제하기 때문에 사용자(유저 모드)가 직접 접근이 불가능하다.
    • 접근 시 system call(시스템 콜)을 통한 커널 모드 전환이 필요하다.
  • 유저 영역
    • 스택 영역, 힙 영역, 데이터 영역, 코드 영역
    • 코드 영역
      • 실행할 수 있는 코드, 기계어로 이루어진 명령어 저장
      • read-only, 데이터가 아닌 CPU가 실행할 명령어가 담기기에 쓰기 금지
    • 데이터 영역
      • 전역 변수와 정적 변수가 저장되는 영역
    • 힙 영역
      • 동적할당된 변수가 저장되는 영역, 프로그래머가 직접 할당 가능
      • 동적할당 : 프로그램이 실행되는 도중에 메모리를 할당하는 것. 동적할당에서 포인터가 저장되는 곳은 스택 영역이다. 메모리 사용 후, 동적할당 해제를 하지 않으면 메모리 누수(memory leak)가 발생할 수 있다.
    • 스택 영역
      • 함수 내에서 지역변수와 매개변수가 저장되는 영역
      • 스택 영역이 생성될 때(함수 실행) 필요한 크기만큼 만들어지고, 데이터 저장
      • 함수가 끝나면 스택 영역 소멸

이중 모드

  • CPU가 명령어를 실행하는 모드를 크게 사용자 모드, 커널 모드로 구분하는 방식
  • 사용자 모드
    • 운영체제 서비스를 제공받을 수 없는 실행 모드
    • 커널 영역의 코드를 실행할 수 없는 실행 모드
    • 자원 접근 불가능
  • 커널 모드
    • 운영체제의 서비스를 제공받을 수 있는 실행 모드
    • 자원 접근을 비롯한 모든 명령어 실행 가능
  • 시스템 호출(시스템 콜, system call)
    • 커널 모드로 전환하여 실행하기 위해 호출
    • 운영체제 서비스를 제공받기 위해 커널 모드로 전환하는 방법
    • 종류
      • 프로세스 관리 : fork(), exit(), waitpid()
      • 파일 관리 : open(), close(), read(), write()
      • 디렉터리 관리 : mkdir(), rmdir()
      • 파일 시스템 관리 : mount(), umount()

프로세스

  • 운영체제로부터 시스템 자원을 할당받는 작업의 단위
  • 메모리에 올라와 실행되고 있는 프로그램의 인스턴스
  • 동적인 개념으로 실행된 프로그램을 의미한다.
  • 프로세스 확인 방법
    • 윈도우 : 작업 관리자
    • 리눅스, macOS : ps 명령어
  • 포그라운드 프로세스(Foreground process)
    • 사용자가 볼 수 있는 공간에서 실행되는 프로세스
  • 백그라운드 프로세스(background process)
    • 사용자와 직접 상호작용이 가능한 프로세스
    • 사용자와 상호작용하지 않고 정해진 일만 수행하는 프로세스 -> 데몬(daemon), 서비스(service)

프로세스 제어 블록(PCB)

  • 모든 프로세스는 실행을 위해 CPU가 필요하다.
  • 하지만 CPU 자원은 한정되어 있기 떄문에, 프로세스들은 돌아가면서 한정된 시간만큼 CPU를 사용해야한다.
  • 프로세스를 관리하기 위해서 PCB 사용
  • 프로세스 관련 정보를 저장하는 자료구조
  • 대표적인 정보
    • 프로세스 ID(PID)
      • 특정 프로세스를 식별하기 위해 부여하는 고유 번호(ex. 학번, 사번)
    • 레지스터 값
      • 프로세스가 자신의 실행 차례가 오면, 이전에 사용한 레지스터 중간 값을 모두 복원한다.
      • 프로그램 카운터, 스택 포인터, ..
    • 프로세스 상태
      • 생성(create), 준비(ready), 실행(running), 대기(waiting), 완료(terminated)
    • CPU 스케줄링 정보
      • 우선 순위, 최종 실행 시각, CPU 점유 시간
      • 프로세스가 언제, 어떤 순서로 CPU를 할당 받을지에 대한 정보
    • 메모리 정보
      • 프로세스가 어느 주소에 저장되어 있는지에 대한 정보
      • 페이지 테이블 정보
    • 사용한 파일과 입출력장치 정보

문맥 교환(context switch)

  • A 프로세스에서 B 프로세스로 넘어 갈 때, 어떤 작업이 수행?
    • 기존 실행 프로세스가 지금까지의 중간 정보를 백업한다.
    • 중간 정보 : context(문맥)
    • 다음 차례가 왔을 때 실행을 재개하기 위해 저장하는 정보
  • 기존 실행 프로세스 문맥을 백업하고, 새로운 프로세스 실행을 위해 문맥을 복구하는 과정

프로세스 상태

  • 생성 상태(create)
    • 이제 막 메모리에 적재되어 PCB를 할당 받은 상태
    • 준비가 완료되면 준비 생태로
  • 준비 상태(ready)
    • 바로 실행 가능하지만, 순서를 기다리는 상태
  • 실행 상태(running)
    • CPU를 할당 받아 실행 중인 상태
    • 할당 시간을 모두 사용하면,(타이머 인터럽트 발생) 준비 상태로 이동
    • 실행 도중 입출력장치를 사용하면 입출력 작업이 끝날 때까지 대기 상태로
  • 대기 상태(waiting)
    • 프로세스가 실행 도중 입출력장치를 사용하는 경우
    • 입출력 작업이 끝나면 준비 상태로 이동
  • 종료 상태(terminated)
    • 프로세스가 종료된 상태
    • PCB 정리


스레드

  • 프로세스를 구성하는 실행 흐름의 단위
  • 하나의 프로세스는 하나 이상의 스레드를 가질 수 있다.
  • 단일 스레드 프로세스 : 실행 흐름 1개
  • 멀티 스레드 프로세스 : 실행 흐름 2개 이상, 여러 명령어 동시 실행 가능
  • 스레드의 구성 요소
    • 스레드 ID, 레지스터 값, 스택 등등
    • 실행에 필요한 최소한의 정보를 갖고 있다.
    • 같은 프로세스에 있는 스레드 끼리 자원을 공유할 수 있다.


 

프로세스 VS 스레드

- 프로세스는 메모리에 올라가는 프로그램으로 운영체제로부터 메모리, 주소 공간 등을 할당 받는다.

- 멀티 프로세스 환경에서는 메모리에 올라간 다양한 프로세스들이 CPU를 선점하며 진행된다.

- CPU 선점과정을 통해 PCB에 각각의 프로세스들이 실행되었던 정보들은 문맥 교환을 통해 저장된다.

- 스레드는 각 프로세스에서 실행 단위를 뜻한다. 하나의 프로세스에 여러 개의 스레드가 동작하는 것을 멀티 스레드라고 한다.

- 각각 스레드는 한 프로세스에서 힙 영역과 데이터 영역을 공유하고, 각 스레드마다 스택과 PC레지스터 값이 따로 존재한다.

- 멀티 스레드는 생성과 관리의 중복을 최소화하고, 멀티 프로세스에 비해 문맥 교환 비용이 낮다.

 

 

멀티 프로세스 vs 멀티 스레드

  • 멀티 프로세스의 프로세스는 자원을 서로 공유하지 않는다.
    • 프로세스 간 통신(IPC)으로, 프로세스 간에도 자원을 주고받을 수 있다.
  • 멀티 스레드에서는 하나의 프로세스 자원을 스레드가 서로 공유한다.

 

멀티 스레드

- 장점 : 여러 프로세스를 동시에 처리하던 일을 자원과 메모리 공유로 자원 소모에 대한 비용 절감

- 또한 프로세스의 문맥 교환과 다르게 캐시 메모리를 비울 필요가 없어 속도가 빠르다.

- 단점 : 여러 자원을 공유하기 때문에, 동기화 문제를 해결하기 위한 작업 필요

 

-> 멀티 프로세스도 다른 프로세스가 점유하고 있는 자원에 대해 접근할 때 동기화 문제가 발생할 수 있다.

- 문재 해결 : 임계 영역으로 동시 접근 방지 -> 세마포어, 뮤텍스

 


CPU 스케줄링

  • 운영체제가 프로세스들에게 공정하고 합리적으로 CPU 자원을 분배하는 것
  • 프로세스 우선순위(priority) 에 따라 프로세스 실행 순서가 정해진다.
  • 스케줄링 큐

선점(preemptive) 스케줄링

  • 프로세스가 CPU를 할당받아 실행 중이어도, 운영체제가 CPU의 사용권을 선점 가능
  • 처리 시간 예측이 어렵다.
  • 잦은 문맥 교환으로 오버헤드 발생 가능성이 있다.
  • CPU 사용 독점 문제를 막을 수 있다.
  • Interrupt, I/O or Event Completion, I/O or Event Wait, Exit

비선점(non-preemptive) 스케줄링

  • 프로세스가 CPU를 점유하고 있으면, 사용을 뺐을 수 없는 방식
  • 필요한 문맥 교환만 일어나기 때문에 오버헤드가 상대적으로 적다.
  • 처리 시간 예측이 쉽다.
  • I/O or Event wait, Exit

프로세스 상태 다이어그램

  • 승인(Admitted) : 프로세스 생성이 가능하여 승인된 상태
  • 스케줄러 디스패치(Scheduler dispatch) : 준비 상태에 있는 프로세스 중 하나를 선택하여 실행
  • 인터럽트(Interrupt) : 예외, 입출력, 이벤트 등이 발생해서 현재 실행 중인 프로세스를 준비 상태로 바꾸고, 해당 작업을 먼저 처리
  • 입출력 또는 이벤트 대기(I/O or event wait) : 실행 중인 프로세스가 입출력이나 이벤트를 처리해야 하는 경우, 입출력/이벤트가 모두 끝날 때 까지 대기 상태로 만드는 것
  • 입출력 또는 이벤트 완료(I/O or event completion) : 입출력/이벤트가 끝난 프로세스를 준비 상태로 전환하여 스케줄러에 의해 선택될 수 있도록 만드는 것

CPU 스케줄링 종류

  • 비선점 스케줄링
    1. FCFS(First Come First Served) 선입 선처리 스케줄링
      • 준비 큐에 삽입된 순서대로 처리하는 비선점 스케줄링
      • 먼저 CPU를 요청한 프로세스부터 CPU 할당
      • 실행 시간이 짧은 것이 뒤로 가면 평균 대기 시간이 길어진다.
    2. SJF(Shortest Job First) 최단 작업 우선 스케줄링
      • 수행 시간이 가장 짧다고 판단되는 작업을 먼저 수행
      • FCFS 보다 평균 대기 시간 감소, 짧은 작업에 유리하다.
  • 선점 스케줄링
    1. RR(Round Roubin) 라운드 로빈
      • FCFS + 타임 슬라이스(time slice) or Time Quantum
      • 타임 슬라이스 : 실행의 최소 단위 시간, 각 프로세스가 CPU를 사용할 수 있는 정해진 시간
      • 정해진 시간을 모두 사용해도, 프로세스가 완료되지 않으면 큐의 맨 뒤에 삽입(문맥 교환)
      • Time Quantum이 크면 FCFS와 같고, 작으면 문맥 교환이 잦아져서 오버헤드 발생
    2. SRT(Shortest Remaining Time) 최소 잔여 시간 우선 스케줄링
      • SJF + RR
      • 정해진 시간만큼 CPU를 사용하고, 다음으로 CPU를 사용할 프로세스를 남은 작업 시간이 가장 적은 프로세스를 선택한다.
    3. Priority Scheduling(우선순위 스케줄링)
      • 프로세스들에 우선순위를 부여하고, 우선순위 높은 프로세스부터 실행
      • 우선순위가 같은 프로세스들은 FCFS 스케줄링
      • 단점 : 우선 순위가 낮은 프로세스를 무한정 기다리는 기아(starvation) 현상
      • Aging 방법으로 기아 현상 해결이 가능하다.
      • Aging : 오랫동안 대시한 프로세스의 우선순위를 점차 높이는 방식
    4. Multilevel-Queue(다단계 큐)
      • 우선순위 스케줄링이 발전된 형태
      • 우선순위별로 준비 큐를 여러 개 사용하는 스케줄링 방식
      • 우선순위가 가장 높은 큐에 있는 프로세스를 먼저 처리하고, 가장 높은 큐가 비어 있으면 그 다음 우선순위 큐에 있는 프로세스를 처리한다.
      • 우선순위가 높은 큐는 작은 Time Quantum, 우선순위가 낮은 큐는 큰 Time Quantum
    5. Multilevel feedback queue(다단계 피드백 큐 스케줄링)
      • 큐 간의 이동이 가능한 다단계 큐 스케줄링
      • 자연스럽게 CPU 집중 프로세스의 우선순위는 상대적으로 낮아지고, 입출력 집중 프로세스의 우선순위는 높아진다.

동기화

  • 프로세스들의 수행 시기를 맞추는 것
  • 실행 순서 제어 : 프로세스를 올바른 순서대로 실행, reader writer problem
    • reader와 writer 프로세스는 아무렇게나 실행 되면 X
  • 상호 배제 : 동시 접근이 안되는 자원에 하나의 프로세스만 접근하게 하기, bank account problem
    • 한 번에 하나의 프로세스만 접근해야 하는 자원에 동시 접근을 피하기 위한 동기화
    • ex. 계좌에 입금할 때 현재 잔액 + 추가 금액
  • 공유 자원 : 여러 프로세스 혹은 스레드가 공유하는 자원
    • ex. 전역 변수, 파일, 입출력장치, 보조기억 장치 등등
  • 임계 구역 : 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역
    • ex. 총합 변수, 잔액 변수
  • 레이스 컨디션(race condition) : 임계 구역에 동시에 접근하면 자원의 일관성이 꺠지는 것

Race Condition

  • 공유 자원에 대해 여러 프로세스가 동시에 접근할 때, 결과값에 영향을 줄 수 있는 상태

동기화 기법

  • 뮤텍스 락, 세마포어, 모니터
  • 뮤텍스 락
    • 상호 배제를 위한 동기화 도구, key를 기반으로 상호 배제
    • 전역 변수 1개, 함수 2개로 구현
    • 자물쇠 역할 : 프로세스들이 공유하는 전역 변수 lock
    • 임계 구역을 잠그는 역할 : acquire 함수
    • 임계 구역의 잠금을 해제하는 역할 : release 함수
    • busy waiting(바쁜 대기) 적용 : 임계 구역이 잠겨 있는지 확인하는 작업을 무한으로 작동
  • 세마포어
    • 일반화된 방식의 동기화 도구
    • 공유 자원이 여러 개 있는 경우에도 적용 가능
    • 멀티프로그래밍 환경에서 공유 자원에 대한 접근을 제한하는 방법
    • 전역 변수 1개, 함수 2개로 구현
    • 전역 변수 S : 임계 구역에 진입할 수 있는 프로세스 개수를 나타내는 변수
    • wait 함수 : 임계구역에 들어가도 되는지, 기다려야 하는지 알려주는 함수
    • signal 함수 : 임계 구역 앞에서 기다리는 프로세스에 가도 된다는 신호를 주는 함수
    • busy waiting(바쁜 대기) 적용 : CPU 사이클 낭비의 단점
      • 계속 반복되는 연산으로 CPU 낭비
      • 해결 방법
        • 사용할 수 있는 자원이 없을 경우 대기 상태로 만든다. -> 해당 프로세스의 PCB를 대기 큐에 삽입
        • 사용할 수 있는 자원이 생겼을 경우 대기 큐의 프로세스를 준비 상태로 만든다. -> 해당 프로세스의 PCB를 대기 큐에서 꺼내 준비 큐에 삽입
wait() {
    while (S <= 0) // 임계 구역에 진입할 수 있는 프로세스 개수가 0 이하면
        ; // 사용 가능한 자원이 있는지 확인하고
    S--; // 임계 구역에 진입할 수 있는 프로세스 개수가 1개 이상이면 S 감소하고 임계 구역 진입
}

signal() {
    S++; // 임계 구역에서의 작업을 마치고 S 증가
        }

 


교착 상태(Dead lock)

  • 두 개 이상의 프로세스나 스레드가 서로 자원을 얻지 못해서 다음 처리를 하지 못하는 상태
  • 무한히 다음 자원을 기다리는 상태
  • 교착 상태 조건
    • 상호 배제 : 한 프로세스가 사용하는 자원을 다른 프로세스가 사용할 수 없는 상태
    • 점유와 대기 : 자원을 할당 받은 상태에서 다른 자원을 할당 받기를 기다리는 상태
    • 비선점 : 어떤 프로세스도 다른 프로세스의 자원을 강제로 빼앗지 못하는 상태
    • 원형 대기 : 프로세스들이 원의 형태로 자원을 대기하는 상태
  • 교착 상태 해결 방법
    • 예방(prevention) : 교착 상태가 발생하지 않도록 발생 조건 중 하나를 없애기
    • 회피(avoidance) : 예방보다 덜 엄격한 제약 조건으로 자원을 좀 더 효율적으로 사용할 수 있도록 해결
      • 은행원 알고리즘 : 프로세스가 자원을 요구할 때, 시스템은 자원을 할당한 후에도 안정 상태인지 사전에 검사하여 교착 상태 회피
    • 회복 : 교착 상태 발생을 인정하고 사후에 조치하는 방식
      • 선점을 통한 회복, 프로세스 강제 종료를 통한 회복
    • 무시 : 교착 상태를 해결할 때, 문맥 교환에 의한 오버헤드로 성능저하가 일어날 수 있어서 무시하는 방법

 

 

메모리 단편화

- 단편화(fragmentation) : 프로세스들이 메모리에 적재되고 해제되는 것이 반복되면, 프로세스들 사이에 사용 못하는 공간이 생긴다.

- 외부 단편화 : 메모리 공간 중 사용하지 못하게 되는 일부 물리 메모리 사이에 남는 공간들을 합쳤을 때 다른 프로세스를 할당할 수 있는 문제

- 내부 단편화 : 프로세스가 사용하는 메모리 공간 내에 사용하지 않는 부분

 

 

페이징

- 페이징 기법으로 논리 메모리는 물리 메모리에 저장될 때 연속되어 저장될 필요 없이 물리 메모리의 남는 프레임에 적절히 배치

- 페이지와 프레임을 대응하는 페이징 테이블 필요(paging table)

- 장점 : 외부 단편화를 해결

- 단점 : 내부 단편화 비중이 늘어난다.

 

 

세그멘테이션

- 페이징처럼 논리, 물리 메모리를 같은 크기의 블록이 아닌 서로 다른 크기의 논리적 단위인 세그먼트로 분할해서 할당

- 각 세그먼트는 연속적인 공간에 저장된다.

- mapping을 위한 segment table 필요

- 필요한 메모리 공간만큼 메모리를 할당하기 때문에 내부 단편화 문제는 없지만, 중간에 메모리를 해제하면 외부 단편화 발생

 

📌 컴퓨터구조

  • 참고 강의 : 혼자 공부하는 컴퓨터구조 + 운영체제

컴퓨터 구조 시작하기

  • 중요한 요소들 : 성능, 용량, 비용
  • 컴퓨터가 이해하는 정보 : 데이터, 언어

데이터

  • 숫자, 문자, 이미지, 동영상과 같은 정적인 정보
  • 컴퓨터는 0과 1로 이루어진 데이터만 이해할 수 있다.

명령어

  • 컴퓨터를 실질적으로 움직이는 정보
  • 데이터는 명령어를 위한 일종의 재료 ex. 명령어 : 1과 2를 더해라
    • 데이터 : 1, 2

컴퓨터의 4가지 핵심 요소

  • CPU, 메모리(주기억장치), 보조기억장치, 입출력장치
  • CPU, Central Processing Unit(중앙처리 장치)
    • 컴퓨터 시스템을 통제하고 프로그램의 연산을 실행하는 컴퓨터의 제어 장치
  • 메모리
    • 현재 실행되는 프로그램의 명령어와 데이터를 저장한다.
    • 메모리에 저장된 값을 효율적으로 접근하기 위해 주소(address) 개념 사용
    • RAM(Random Access Memory) : 휘발성, 작업 중인 파일을 한시적으로 저장한다. 전원이 차단되면 데이터가 사라진다. 일반적으로 메모리는 RAM을 지칭한다.
    • ROM(Read Only Memory) : 비휘발성, 컴퓨터에 지시사항을 영구하게 저장한다. 전원이 차단되어도 데이터가 사라지지 않는다.
  • 보조기억장치 : 주기억장치보다 느리지만, 데이터를 영구적으로 보관할 수 있는 장치
    • HHD(Hard Disk Driver), SSD(Solid State Driver)
    • 메모리는 실행할 정보를 저장하고, 보조기억장치는 보관할 정보를 저장한다.
  • 입출력장치 : 컴퓨터 외부에 연결되어 컴퓨터 내부와 정보를 교환할 수 있는 부품

 

  • 메인 보드(Main board)
    • 컴퓨터의 핵심 부품들을 연결한다.
    • 메인 보드의 부품들은 버스(bus)라는 통로를 이용해서 정보를 주고받을 수 있다.
  • 시스템 버스
    • 메인 메모리와 마이크로프로세서 사이 데이터를 전달하기 위해 사용되는 커넥터와 케이블로 구성된 통로
    • 컴퓨터 시스템의 주요 부품 사이에서 데이터와 제어 시그널을 위한 통신을 제공한다.
    • 구성 요소 : address bus(주소 버스), control bus(제어 버스), data bus(데이터 버스)
    • 주소 버스
      • CPU가 주기억 장치나 입출력 장치로 기억장치 주소를 전달하는 통로.
      • 단방향 버스(주소만 전달)
      • 물리적 주소를 찾는 목적으로 사용.
      • 모든 주소 버스는 bit 형태로 CPU 또는 DMA(Direct Memory Access)에 의해 사용
    • 제어 버스
      • CPU에 의해 사용되고, 컴퓨터 내에 포함된 장치들과의 통신에 사용된다.
      • 데이터 버스와 주소 버스를 제어하기 위해 제어 신호들을 전송하는 통로
      • 양방향 버스(읽기, 쓰기 동작 모두 수행)
    • 데이터 버스
      • 데이터 전달에 사용
      • 양방향 버스

CPU 구성 요소

  • ALU(Arithmetic and Logical Unit)
    • 산술논리연산장치
    • 사칙연산 같은 두 숫자의 산술 연산 계산
    • 배타적 논리합, 논리곱, 논리합 같은 논리 연산 계산
  • 제어 장치(Control Unit, CU)
    • 프로세서의 조작을 지시하는 CPU 의 한 요소
    • 제어 신호를 보내고, 명령어들을 읽고 해석, 데이터 처리를 위한 시퀀스를 결정
    • 제어 신호 : 메모리 읽기 or 메모리 쓰기
  • 레지스터(Register)
    • CPU 내부에 위치한 고속 메모리
    • 바로 사용할 수 있는 데이터를 담고 있는 영역
    • PC, Program Counter(프로그램 카운터)
      • 메모리에서 가져올 명령어의 주소
    • IR, Instruction Register(명령어 레지스터)
      • 해석할 명령어(메모리에서 방금 가져온 명령어)
    • MAR, Memory Address Register(메모리 주소 레지스터)
      • 메모리의 주소를 저장
    • MBR, Memory Buffer Register(메모리 버퍼 레지스터)
      • 메모리와 주고받을 값(데이터 명령어)
    • 플래그 레지스터
      • 연산 결과 또는 CPU 상태에 대한 부가적인 정보
    • 범용 레지스터
      • 다양하고 일반적인 상황에서 자유롭게 사용
      • EAX(Accumulator), EBX(Base), ECX(Counter), EDX(Data)...
    • 스택 포인터
      • 스택 주소 지정에 사용, 스택의 top
    • 베이스 레지스터
      • 기존 주소 지정에 사용

명령어 실행 예시

  • 제어 장치는 1번지의 명령어를 읽기 위해서 메모리에 읽기 제어 신호를 보낸다.

  • 메모리는 1번지에 있는 명령어를 CPU 에게 전달, 이 명령어는 레지스터에 전달된다.
  • 레지스터에 들어온 명령어를 제어장치가 해석한다.
  • 레지스터에 있는 명령어(3번지와 4번지를 더하기)에서 3번지와 4번지의 데이터를 얻기 위해 메모리에 메모리 읽기 제어 신호를 보낸다.

  • 메모리에서 3번지와 4번지의 데이터를 CPU 에게 전달, 각각 레지스터에 데이터가 저장된다.
  • ALU 에서 레지스터에 있는 데이터로 계산
  • 계산한 결과 값은 레지스터에 저장된다.
  • 명령어 실행 종료


데이터 표현

  • 정보(information) : 가공된 데이터를 의미한다. 어떤 사물에 대한 소식이나 자료
  • 데이터(data) : 가공되지 않은 데이터.
  • 정보 단위

  • 워드(word)
    • CPU 가 한 번에 처리할 수 있는 정보의 크기 단위
  • 이진법(Binary)
    • 0과 1로 수를 표현하는 방법
    • 숫자가 1을 넘어가는 시점에 자리
    • 2의 보수(음수 표현) : 모든 0과 1을 뒤집고 1을 더한다.
    • ex. 11(2) = 00(2) = 01(2)
    • 양수인지 음수인지 구분하는 방법? : CPU에 있는 레지스터인 플래그(flag)로 구분한다.
    • 접두어 : 0b

  • 16진법(Hexadecimal)
    • 십진법보다 이진수와의 변환이 간단해서 사용
    • 십진수 : 16 = 16진수 : 10
    • 접두어 : 0x


문자 집합(Character Set)

  • 컴퓨터가 이해할 수 있는 문자의 모음
  • 인코딩(Encoding) : 코드화 => 문자를 0, 1으로 이루어진 문자 코드로 변환
  • 디코딩(Decoding) : 코드 해석 => 0, 1으로 이루어진 문자 코드를 문자로 변환

아스키 코드(ASCII : American Standard Code for Information Interchange)

  • 알파벳, 아라비아 숫자, 일부 특수 문자 및 제어 문자
  • 정보 교환용 7비트 부호 체계
  • 8 비트 중 1비트는 오류 검출을 위해 사용되는 패리티 비트(Parity Bit)
  • 7 비트로 하나의 문자 표현 : 2^7 = 총 128개의 부호 사용

유니코드(Unicode)

  • 전 세계의 모든 문자 집합
  • 인코딩 방식 : utf-8, utf-16, utf-32

UTF-8

  • Unicode Transformation Format
  • 가변 길이 인코딩 : 한 글자가 1~4바이트 중 하나로 인코딩 될 수 있다.

고급 언어와 저급 언어

  • 고급 언어(High-Level Language)
    • 사람 중심 언어
    • 실행을 위한 번역이 필요하다.
    • 컴파일 언어, 인터프리터 언어
  • 저급 언어(Low-Level Language)
    • 기계 중심 언어
    • 빠른 실행 속도
    • 기계마다 다른 코드를 가진다.
    • 기게어(Machine Language) : 0과 1로 이루어진 언어
    • 어셈블리어(Assembly Language) : 0과 1로 이루어진 기계어를 읽기 편한 형태로 번역한 언어
      • push rbp, pop rbp, ret

컴파일 언어

  • 소스 코드(고급 언어) -> 컴파일러(컴파일) -> 목적 코드(저급 언어)
  • 소스코드를 모두 기게어로 변환하기 때문에 인터프리터보다 시간이 소요
  • 런타임 상황에서는 이미 모든 소스코드가 변환되어 있어 빠른 실행 가능
  • C, C++

인터프리터 언어

  • 소스코드 -> 인터프리터 -> 목적 코드
  • 기계어로 변환하는 과정에서 인터프리터에 의해 한 줄씩 해석, 실행한다.
  • Python, Ruby

명령어의 구조

  • 명령코드(Operation Code) : 명령어가 수행할 연산
  • 오퍼랜드(Operand) : 연산에 사용할 데이터 또는 데이터의 주소
  • 오퍼랜드는 1개도 없을 수도 있고, 여러 개를 가질 수도 있다.

  • 연산 코드의 종류
    • 데이터 전송
      • MOVE : 데이터를 옮겨라
      • STORE : 메모리에 저장해라
      • LOAD(FETCH) : 메모리에서 CPU로 데이터를 가져와라
      • PUSH : 스택에 데이터를 저장해라
      • POP : 스택의 최상단 데이터를 가져와라
    • 산술/논리 연산
      • ADD, SUBTRACT, MULTIPLY, DIVIDE : 사칙 연산
      • INCREMENT, DECREMENT : 오퍼랜드에 1 증감, 차감
      • AND, OR, NOT
      • COMPARE : 두 개의 숫자 또는 TRUE, FALSE 값을 비교해라
    • 제어 흐름 변경
      • JUMP : 특정 주소로 실행 순서 이동
      • CONDITIONAL JUMP : 조건에 부합하면 특정 주소로 실행 순서 이동
      • HALT : 프로그램의 실행 중지
      • CALL : 되돌아올 주소 저장, 특정 주소로 실행 순서 이동
      • RETURN : CALL을 호출할 때 저장한 주소로 리턴
    • 입출력 제어
      • READ(INPUT) : 특정 입출력 장치에서 데이터를 읽어라
      • WRITE(OUTPUT) : 특정 입출력 장치에서 데이터를 써라
      • START IO : 입출력 장치를 시작해라
      • TEST IO : 입출력 장치 상태를 확인해라

컴파일 과정

  • C 언어
    • test.c(소스 코드) -> 전처리기(preprocessor) -> 컴파일러(compiler) -> 어셈블러(assembler) -> 링커(linker) -> test.exe(실행 파일)

명령어 사이클

  • 프로그램 속 명령어들은 일정한 주기를 반복하면서 실행한다.
  • 이 주기를 명령어 사이클 이라고 한다.
  • 기본적인 명령어 사이클 : 인출 - 실행 - 인출 - 실행 ...
  • 추가적인 메모리 접근이 필요한 경우? : 간접 주소 방식을 사용해서 필요한 데이터를 가져온다.
  • 인터럽트(interrupt) : CPU 가 실행해야 하는 흐름을 멈추는 작업
  • 인출 사이클 -> 간접 사이클 -> 실행 사이클 -> 인터럽트 사이클

인터럽트(Interrupt)

  • 동기 인터럽트(예외) : CPU가 예기치 못한 상황을 접했을 때 발생
  • 비동기 인터럽트(하드웨어 인터럽트) : 주로 입출력장치에 의해 발생
    • 효율적인 명령어 처리를 위해 사용한다. 만약 사용하지 않는다면, 프린트 완료 여부 확인을 위해 주기적으로 확인해야 하는 비용이 발생한다.
    • ex. 세탁기 완료 알림, 전제레인지 조리 알림

클럭(Clock)

  • 컴퓨터의 부품들이 움직이는 시간 단위
  • 클럭 주기 : CPU의 클럭이 한 사이클에 걸리는 시간
  • 클럭 속도 : 헤르츠(Hz) 단위로 측정
  • 헤르츠(Hz) : 1초에 클럭이 반복되는 횟수
    • ex. 클럭이 1초에 100번에 반복되면 100Hz
  • 일반적으로 클럭 속도를 높이면 CPU 속도가 빨라지긴 하지만 과해지면 발열 발생
    • 다른 방법으로는 코어, 스레드 수를 증가시킨다.

코어(Core)

  • 명령어를 실행하는 부품
  • 멀티 코어 : 두 개 이상의 코어를 가지고 있는 CPU
  • 코어가 많다고 무조건 속도가 향상되는 것이 아니다.

스레드(Thread)

  • 프로그램 실행 흐름의 단위
  • 하드웨어적 스레드, 소프트웨어적 스레드가 있다.
  • 하드웨어워 스레드 : 하나의 코어가 동시에 처리하는 명령어 단위
  • 소프트웨어 스레드 : 하나의 프로그램에서 독립적으로 실행되는 단위

명령어 파이프라인

  1. 명령어 인출(Instruction Fetch)2
  2. 명령어 해석(Instruction Decode)
  3. 명령어 실행(Execute Instruction)
  4. 결과 저장(Write Back)
  • 같은 단계가 겹치지 않으면 각자 단계를 동시에 실행할 수 있다.
  • 동시에 여러 개의 명령어를 겹쳐 실행하는 기법이다.

<


명령어 집합

  • 명령어 집합(구조) : CPU가 이해할 수 있는 명령어들의 모음
  • 일반적으로 인텔의 CPU는 X86 명령어 집합, 애플의 CPU는 ARM 명령어 집합을 사용
  • CISC(Complex Instruction Set Computer)
    • CPU를 설계하는 방식
    • 복잡한 명령어 집합을 갖는 CPU 아키텍처
    • 가변 길이 명령어
    • 메모리를 아낄 때 사용했지만, 명령어 파이프라이닝이 불리하다.
  • RISC(Reduced Instrunction Set Computer)
    • CPU를 설계하는 방식
    • 간단하고 적은 종류의 명령어와 주소 지정 모드를 사용
    • 고정 길이 명령어
    • 메모리 접근 최소화, 레지스터 활용

저장 장치 계층 구조

  • CPU 와 가까운 저장 장치는 빠르고, 멀리 있는 저장 장치는 느리다.
  • 속도가 빠른 저장 장치는 저장 용량이 적고, 가격이 비싸다.
  • CPU 에 가까운 순서 : 레지스터 > 메모리(RAM) > USB
  • 캐시 메모리
    • CPU 와 메모리 사이에 위치
    • 레지스터보다 용량이 빠르고, 메모리보다 빠른 SRAM 기반 저장 장치
    • 메모리에 계속 접근하는 것 보다 일부 데이터를 캐시 메모리에서 저장해둔 뒤 사용
    • 캐시 메모리는 CPU(코어)에 위치 하거나 CPU와 메모리 사이에 위치
      • L1, L2 코어에 위치
      • L3 CPU와 메모리 사이에 위치
    • 멀티 코어 프로세서에서는 각 코어에 위치한 캐시 메모리가 다른 경우가 있기 때문에, 싱크를 맞춰주는 작업이 필요하다.
    • CPU가 자주 사용할 법한 메모리를 저장
      • 캐시 히트 : CPU가 캐시 메모리에 저장된 값을 활용(예측 성공)
      • 캐시 미스 : CPU가 메모리에 접근해야 하는 경우(예측 실패)
    • 참조 지역성의 원리
      • CPU가 최근에 접근했던 메모리 공간에 다시 접근하려는 경향
      • CPU가 접근한 메모리 공간 근처를 접근하려는 경향

+ Recent posts