컴퓨터 시스템 : A Programmer's Perspective - Chapter 1

김수환·2024년 9월 19일
0

컴퓨터 시스템

컴퓨터는 어떻게 작동하는가? 단순히 코드가 입력되면 코드가 작은 난쟁이로 변해 컴퓨터 속을 헤집고 다니며 우리의 명령어를 충실히 수행하는 것일까?

이 책은 이러한 물음에 명쾌한 해답을 줄 수 있는 책으로, 하드웨어가 어떻게 구성되고 그 안에서 코드란 것이 어떤 환경에서 어떤 식으로 작동하게 되는지 미시적인 관점에서 근본적인 이해를 돕는 책이다.

다만 기본 영어 원서인 책을 한글로 번역하는 과정에서 다소 의역과 번역체가 난무하기에 비전공자가 바로 공략하기엔 난해할 수 있다.

1장. 컴퓨터 시스템으로의 여행

1.1 정보는 bit와 context로 이루어진다.

  • 소스 프로그램은 0 또는 1로 표시되는 '비트'들의 연속, '바이트'라는 8비트 단위로 구성된다.
  • 각 바이트는 프로그램의 텍스트 문자를 나타낸다.
  • 오로지 아스키(ASCII) 문자로만 이루어진 파일 : 텍스트 파일
  • 그 외 다른 모든 파일 -> 바이너리 파일
  • context에 따라 프로그램은 다른 기능과 의미를 지닐 수 있다.
  • context :
    PC, register file, main memory 현재 값 등을 포함. 프로그램이 구동되는 환경 정보를 담은 것.

컨텍스트는 컴퓨터 내부에서 볼 때, 프로세서 안에 있는 레지스터, 플래그 등의 현재 값/상태들의 집합을 말함

1.2 프로그램은 다른 프로그램에 의해 번역된다.

  • 프로그램이 번역되는 기본적인 구조 (아래 순서)

  • source program(xx.c) ->
    [preprocessor] Modified source program(xx.i) ->
    [complier] assembly program(xx.s) ->
    [assembler] Relocatable object programs(xx.o) ->
    [linker] Executable object program(xx)

  • [preprocessor] : # 문자로 시작하는 directive에 따라 수정. ex. #include<stdio.h> : 시스템 헤더파일인 stdio.h를 프로그램 문장에 직접 삽입하라.

  • [complier] : 어셈블리어로 변환

  • [assembler] : 기계어 인스트런션으로 번역

  • [link] : object programs를 통합하여 실행파일로 변환

항목별 상세 설명

  1. 전처리 (Preprocessing)
    설명: 소스 코드에서 전처리 명령어(예: #include, #define 등)를 처리하는 단계입니다. 매크로 치환, 파일 포함, 조건부 컴파일 등의 작업이 이루어집니다.
    결과: 전처리된 소스 코드가 생성됩니다.
  2. 컴파일 (Compilation)
    설명: 전처리된 소스 코드를 어휘 분석, 구문 분석, 의미 분석 과정을 통해 어셈블리어(Assembly Code)로 변환하는 단계입니다.
    어휘 분석 (Lexical Analysis): 소스 코드를 토큰으로 변환합니다.
    구문 분석 (Syntax Analysis): 토큰이 언어의 문법 규칙에 맞는지 확인하고, 구문 트리를 생성합니다.
    의미 분석 (Semantic Analysis): 변수와 타입 검사를 통해 의미적으로 오류가 없는지 확인합니다.
    결과: 어셈블리어 코드가 생성됩니다.
  3. 어셈블리 (Assembly)
    설명: 어셈블리어 코드를 기계어(Object Code)로 변환하는 단계입니다. 어셈블러(Assembler)가 어셈블리어 코드를 CPU가 실행할 수 있는 바이너리 기계어로 변환합니다.
    결과: 객체 파일(Object File)이 생성됩니다. 이 파일은 컴퓨터에서 직접 실행 가능한 기계어로 구성되어 있지만, 다른 객체 파일과 연결되어야 완전한 프로그램이 됩니다.
  4. 링킹 (Linking)
    설명: 여러 객체 파일(Object Files)과 라이브러리들을 연결하는 단계입니다. 링커(Linker)는 각 객체 파일에 정의된 기호와 참조된 기호를 해결하여 실행 가능한 최종 프로그램(Executable)을 생성합니다.
    결과: 완전한 실행 파일이 생성됩니다.
  5. 로딩 (Loading)
    설명: 링커에 의해 생성된 실행 파일을 메모리에 적재하여 프로그램을 실행하는 단계입니다. 로더(Loader)가 실행 파일을 메모리에 배치하고, 운영 체제에 의해 프로그램이 실행됩니다.
    결과: 프로그램이 메모리에 적재되고, 실행을 준비합니다.

단계 요약:

전처리 → 전처리 명령어 처리
컴파일 → 소스 코드를 어셈블리어로 변환
어셈블리 → 어셈블리어를 기계어(객체 파일)로 변환
링킹 → 객체 파일을 연결하여 실행 파일 생성
로딩 → 실행 파일을 메모리에 로드하고 실행

1.3 컴파일 시스템의 동작 원리 이해

  • 프로그램 성능 최적화 : 프로그램 성능 최적화를 위해선 컴파일러가 어떻게 작동하는지 이해하는 것이 필요하다.
    ex. switch문과 if-else문의 비교 후 적합한 구문 사용해야할 때. (3장에서 계속)
  • 링크 에러의 이해 : 링크 과정에서 발생할 수 있는 에러를 이해하고 대비할 줄 알아야 한다. (7장에서 계속)
  • 보안의 헛점 피하기 : 인터넷과 네트워크를 사용할 때 발생 가능한 보안의 취약점을 미리 알고서 대처해야한다. 스택체제나 버퍼 오버플로우 취약성을 어셈블리어 학습의 일부분으로 다룬다. (3장에서 계속)

프로그램 성능 최적화를 위한 컴파일 옵션들

  1. 컴파일러 최적화 옵션 사용
  • 예시: -O1, -O2, -O3 또는 -Ofast와 같은 컴파일러의 최적화 플래그를 사용하는 것.
  • 설명: 대부분의 컴파일러(GCC, Clang, MSVC 등)는 다양한 수준의 최적화 플래그를 제공합니다.
-O1: 기본적인 최적화로, 코드 크기를 줄이고 약간의 성능 향상을 제공합니다.

-O2: 더 적극적인 최적화로, 실행 성능을 크게 향상시키지만 컴파일 시간이 길어질 수 있습니다.

-O3: 더 많은 루프 최적화와 같은 고급 최적화를 포함하여 최대 성능을 목표로 합니다.

-Ofast: 매우 공격적인 최적화로, 코드의 안전성을 포기하고 성능을 최대한 끌어올리는 옵션입니다.
  • 결과: 위와 같은 옵션들을 사용하면 프로그램이 더 빠르게 실행되며, 메모리 사용량이 줄어드는 등의 성능 향상을 기대할 수 있습니다.
  1. 인라인 함수 사용 (Function Inlining)
  • 예시: 작은 함수에 대해 컴파일러가 자동으로 인라인 처리를 하는 경우.
  • 설명: 함수 호출이 많은 프로그램에서는 함수 호출 오버헤드가 성능 저하의 원인이 될 수 있습니다. 컴파일러는 작은 함수들을 인라인으로 처리하여 함수 호출 오버헤드를 제거할 수 있습니다. inline 키워드를 사용하거나, 컴파일러가 최적화를 자동으로 처리할 수 있습니다.
  • 결과: 함수 호출 오버헤드가 줄어들어 성능이 향상됩니다. 특히, 짧고 자주 호출되는 함수에서 효과적입니다.
  1. 루프 언롤링 (Loop Unrolling)
  • 예시: -funroll-loops 플래그를 사용하여 루프 언롤링을 활성화하는 경우.
  • 설명: 루프의 반복 횟수가 많을 때, 컴파일러는 반복 횟수를 줄이기 위해 루프 언롤링(Loop Unrolling)을 적용할 수 있습니다. 루프 내부의 연산을 여러 번 복사하여 한 번에 여러 작업을 수행하도록 코드가 재작성됩니다.
  • 결과: 루프에서 반복적인 연산을 줄여 실행 시간을 단축시키고, CPU 파이프라인을 더 효율적으로 사용할 수 있습니다.
  1. 메모리 접근 최적화 (Cache Optimization)
  • 예시: 컴파일러가 데이터 구조의 배치를 최적화하거나, 루프 내에서 데이터를 재사용하도록 최적화하는 경우.
  • 설명: 캐시 미스(cache miss)가 성능 저하의 주요 원인일 수 있습니다. 컴파일러는 데이터를 효율적으로 캐시에 배치하거나, 데이터 지역성(Locality of Reference)을 극대화하도록 코드 구조를 최적화할 수 있습니다.
  • 결과: 메모리 접근 시간을 줄여 프로그램 실행 속도가 크게 개선됩니다.
  1. 데드 코드 제거 (Dead Code Elimination)
  • 예시: -O2 이상의 최적화에서 컴파일러가 자동으로 사용되지 않는 코드를 제거하는 경우.
  • 설명: 컴파일러는 실행되지 않거나 결과에 영향을 주지 않는 코드를 찾아 제거할 수 있습니다. 예를 들어, 사용되지 않는 변수나 실행되지 않는 조건문이 있을 때 컴파일러가 이를 제거하여 불필요한 명령어를 줄입니다.
  • 결과: 코드 크기가 줄어들고, 불필요한 연산이 사라지면서 성능이 향상됩니다.
  1. 벡터화 (Vectorization)
  • 예시: -ftree-vectorize 플래그를 사용하여 컴파일러가 자동으로 벡터화 작업을 하는 경우.
  • 설명: 벡터화는 데이터를 병렬로 처리하는 방식으로, 컴파일러가 루프 내에서 한 번에 여러 데이터를 처리하도록 최적화하는 기술입니다. SIMD(Single Instruction Multiple Data) 명령어를 사용하여 한 번에 여러 연산을 처리할 수 있습니다.
  • 결과: 특히, 대량의 데이터 처리가 필요한 계산 작업에서 성능이 크게 개선됩니다.
  1. 지연 연산 (Lazy Evaluation)
  • 예시: 컴파일러가 조건에 따라 필요하지 않은 계산을 지연시키거나 생략하는 경우.
  • 설명: 지연 연산은 값이 실제로 필요할 때까지 계산을 미루는 전략입니다. 이로 인해 불필요한 연산을 피할 수 있으며, 컴파일러가 이를 자동으로 최적화하는 경우가 많습니다.
  • 결과: 불필요한 계산을 줄여 성능을 향상시킵니다.
  1. 플랫폼별 최적화 (Platform-Specific Optimization)
  • 예시: -march=native 플래그를 사용하여 컴파일러가 현재 CPU 아키텍처에 맞는 최적화를 수행하는 경우.
  • 설명: CPU마다 고유한 명령어 집합이 있습니다. -march=native를 사용하면 컴파일러가 실행될 시스템의 CPU 특성에 맞게 최적화를 수행합니다. 예를 들어, 최신 CPU에서는 AVX 명령어 집합 등을 활용하여 성능을 극대화할 수 있습니다.
  • 결과: 시스템 하드웨어에 맞춰 더 빠르고 효율적인 코드를 생성할 수 있습니다.
  1. 프로파일 기반 최적화 (Profile-Guided Optimization, PGO)
  • 예시: -fprofile-generate 및 -fprofile-use 플래그를 사용하여 프로파일 기반 최적화를 적용하는 경우.
  • 설명: 프로그램 실행 중 성능 병목을 일으키는 부분을 분석하고, 이를 바탕으로 컴파일 시 성능이 중요한 부분에 대해 추가 최적화를 수행합니다. PGO는 실제 실행 데이터를 기반으로 최적화하기 때문에 더 정밀한 성능 개선을 제공합니다.
  • 결과: 가장 많이 사용되는 코드에 더 높은 최적화가 적용되어 성능이 향상됩니다.

결론

이와 같은 컴파일 시스템 최적화 방법을 활용하면, 프로그램 성능을 더욱 효과적으로 개선할 수 있습니다. 컴파일러는 소스 코드를 자동으로 분석하고 다양한 최적화를 적용하여 성능을 높일 수 있는 강력한 도구입니다. 최적화는 성능, 코드 크기, 실행 시간 등의 목표에 따라 다르게 설정될 수 있으며, 그 결과 실행 성능을 크게 향상시킬 수 있습니다.

1.4 프로세서는 메모리에 저장된 인스트런셕을 읽고 해석한다

  • 시스템의 하드웨어 구조

    • 버스

      • 컴포넌트 간 바이트 정보 전송하는 전기적 배선군
        (컴퓨터의 여러 하드웨어 구성 요소들 간에 데이터를 주고받는 데 사용되는 통로)
        (명령어와 주소를 전송하는 중간 매개체 역할)

      • 버스는 일정 크기의 바이트 단위(1 word)로 데이터 전송하도록 설계됨. 운영체제에 따라 32비트, 64비트 등으로 나뉨.

        • 버스의 종류
          • 데이터 버스 (Data Bus): 프로세서와 메모리, I/O 장치 간에 데이터를 실제로 전달하는 역할을 합니다. 일반적으로 양방향 버스입니다.
          • 주소 버스 (Address Bus): 프로세서가 데이터를 읽거나 쓸 위치를 지정하는 데 사용됩니다. 메모리나 I/O 장치의 주소 정보를 전송합니다. 일반적으로 단방향 버스입니다.
          • 제어 버스 (Control Bus): 명령과 제어 신호를 전달하는 역할을 합니다. 예를 들어, 읽기/쓰기 신호, 인터럽트 신호 등이 여기에 해당합니다.
    • 입출력 장치

      • 시스템과 외부세계와의 연결을 담당하는 장치들. ex. 키보드, 마우스, 디스플레이, 디스크 드라이브 (6장, 10장에서 계속)
      • 입출력 장치와 프로세서/메모리 간의 데이터 교환을 위해서는 입출력 인터페이스가 필요합니다. 여기에는 메모리 맵드 I/O, 포트 I/O 등의 방식이 포함됩니다.
    • 메인 메모리

      • 프로세서가 프로그램 실행하는 동안 데이터와 프로그램 임시 저장하는 공간.
      • 흔히 RAM(Random Access Memory)으로 불리며, 컴퓨터 시스템에서 가장 중요한 저장 공간
      • DRAM(Dynamic Random Access Memory)로 구성. 메모리는 연속적인 바이트의 배열로 0부터 시작하는 고유의 주소(인덱스)를 가짐. (6장에서 계속)
    • 프로세서

      • 일명 CPU
      • 메인 메모리, 레지스터 파일, 수식/논리 처리기(ALU)를 순환하며 연산 담당.
      • 메인 메모리에 저장된 인스트럭션들을 해독하는 엔진.
      • 프로세서 중심에 워드 크기의 저장장치(register), 일명 program counter(PC)가 있다.
      • 어느 한 시점에 PC는 메모리의 기계어 인스트럭션을 가리킨다.

      역할

      • 명령어 처리: 프로그램의 명령어를 해석하고 실행합니다.
      • 연산 수행: 산술 및 논리 연산을 수행합니다.
      • 데이터 이동: 주 메모리나 입출력 장치로부터 데이터를 읽고, 연산 결과를 저장하거나 전송합니다.

      구성 요소

      • 연산 논리 장치(ALU: Arithmetic Logic Unit): 산술 및 논리 연산을 처리하는 부분입니다.
      • 제어 장치(Control Unit): 명령어를 해석하고, ALU 및 다른 장치들이 명령을 수행하도록 지시합니다.
      • 레지스터 (Register): 프로세서 내부에서 연산 중인 데이터나 주소 정보를 저장하는 초고속 메모리입니다.
      • 캐시 메모리: 프로세서와 주 메모리 간의 속도 차이를 줄이기 위해 사용되는 고속 메모리입니다. 가장 자주 사용되는 데이터와 명령어를 저장합니다.
      • 제어: 컴퓨터 시스템의 모든 장치들을 제어하고, 각 장치 간의 작업 조율을 담당합니다.

      프로세서의 종류

      • 단일 코어 프로세서: 하나의 코어로 명령어를 처리하는 프로세서.
      • 멀티 코어 프로세서: 여러 개의 코어가 병렬로 명령어를 처리하는 프로세서. 성능을 향상시키기 위해 멀티코어 구조가 일반적입니다.

1.5 캐시의 중요성

캐시 메모리

  • 속도가 빠른 장치와 느린 장치 사이에서 속도차에 따른 병목 현상을 줄이기 위한 범용 메모리를 지칭. 데이터 접근 속도를 향상시키기 위해 사용되는 고속 메모리입니다.
  • 캐시는 주로 프로세서(CPU)와 주 메모리(RAM) 간의 속도 차이를 줄이는 역할을 합니다. 프로세서가 주 메모리보다 훨씬 빠르게 동작하기 때문에, 메모리에서 데이터를 읽어오거나 쓸 때 발생하는 지연을 줄이는 것이 캐시의 주요 목적입니다.

캐시의 역할

  • 데이터와 명령어 저장: 프로그램이 실행되면서 자주 사용되는 데이터나 명령어를 임시로 저장합니다.
  • 프로세서와 메모리 간 속도 차이 완화: 캐시는 주 메모리보다 훨씬 빠르게 접근할 수 있기 때문에, 프로세서가 자주 필요한 데이터를 빠르게 제공하여 성능 저하를 방지합니다.
  • 메모리 접근 최적화: 캐시는 지역성(Locality of Reference) 원리에 기반하여 데이터를 관리하는데, 이는 시간적 지역성과 공간적 지역성으로 설명할 수 있습니다.
    • 시간적 지역성(Temporal Locality): 최근에 사용된 데이터가 가까운 미래에 다시 사용될 가능성이 높음.
    • 공간적 지역성(Spatial Locality): 한 번 접근한 데이터의 주변 데이터가 곧 사용될 가능성이 높음.

캐시의 구조

캐시는 일반적으로 다단계(Multi-level) 구조로 되어 있으며, 각 단계마다 속도와 크기가 다릅니다:

  • L1 캐시 (Level 1 Cache):
    프로세서 코어 내부에 위치하며, 가장 작은 크기(수십 KB)와 가장 빠른 속도를 가집니다.
    데이터를 거의 즉각적으로 제공할 수 있는 고속 메모리입니다.
    각 코어마다 독립적으로 존재합니다.

  • L2 캐시 (Level 2 Cache):
    L1 캐시보다 크고 느리지만 여전히 매우 빠름(수백 KB에서 수 MB).
    L2 캐시는 각 코어마다 독립적으로 존재하거나, 여러 코어가 공유할 수도 있습니다.

  • L3 캐시 (Level 3 Cache):
    L2 캐시보다 더 크고 느리지만 여전히 주 메모리보다 빠름(몇 MB에서 수십 MB).
    일반적으로 여러 코어가 공유하는 캐시입니다.

  • L4 캐시 (일부 고성능 시스템에서 존재):
    드물게 사용되며, 메모리와의 접근을 더 빠르게 하기 위한 추가적인 캐시로 매우 큰 크기(수백 MB 이상)일 수 있습니다.

  • 웬만한 프로세서에서는 L3 캐시 메모리를 달고있지 않다. L2 캐시로 충분히 커버할 수 있기 때문이다. intel core2 duo나 quad에는 L3 캐시가 없지만, 코어 i7에는 8MB를 달아뒀다. L1/L2 캐시 메모리 정도만 CPU 성능에 직접적인 영향을 미치기에 L3 캐시는 크게 신경쓰지 않는것이 일반적인 추세다. L3 캐시는 CPU가 아닌 메인보드에 내장되는 경우가 더 많다.

캐시의 특징

  • 속도: 캐시는 프로세서와 매우 가깝게 위치하여, 주 메모리보다 훨씬 빠르게 데이터에 접근할 수 있습니다.
  • 크기: 캐시는 매우 빠르지만, 그 크기는 제한적입니다. 빠른 속도를 유지하기 위해 주 메모리보다 훨씬 작습니다.
  • 비휘발성: 캐시는 휘발성 메모리로, 전원이 꺼지면 캐시 내의 데이터는 사라집니다.
  • 지역성(Locality) 원리 활용: 캐시는 시간적 및 공간적 지역성을 기반으로 데이터를 관리하여, 자주 사용될 데이터를 빠르게 제공할 수 있습니다.
  • 보통 프로그래머가 직접 제어할 수 없으며 CPU에 의해 자동으로 통제된다. 캐시가 있든 없든 프로그래머와 외부 사용자에게 보이는 결과는 동일하다. 이러한 특성을 사용자에게 투명(Transparent)하다고 한다.

1.6 저장장치들은 계층구조를 이룬다

작고 빠른 상위 레벨 저장장치는 보다 크고 느린 하위 레벨 저장장치의 캐시 역할을 한다.

일반적인 컴퓨터 프로그램의 구동에는 레지스터, 캐시, RAM의 세 가지 기억 장치를 사용한다. 이들은 SSD와 HDD보다 처리 속도가 훨씬 빠른 기억 장치로, '주 기억장치'라고 부른다.

예를 들어, 지금 이 문서를 읽는 동안 여러분의 컴퓨터(또는 같은 기능을 하는 모바일 기기)는 웹 브라우저를 구동하고 있다.

이때 웹 브라우저는 RAM과 캐시, CPU를 통해 열심히 정보를 읽고 쓰는 중이다.
그 뒤 웹 브라우저를 끄고 게임을 할 때는 어떨까? 웹 브라우저는 더 이상 구동되지 않지만, 필요할 때 언제든지 다시 실행할 수 있도록 SSD, HDD에 브라우저 프로그램의 데이터는 남아 있다. 그러나 지금 당장 사용하고 있지 않기 때문에 RAM 이상의 처리 성능을 지닌 기억장치에는 웹 브라우저가 이미 들어있지 않다. 주 기억 장치는 게임을 실행하느라 바쁘다.

메모리 특성인 용량, 접근 속도, 비용 간에는 상호 절충(tradeoff) 관계가 있다.

  • 접근 시간이 짧을 수록 비트당 비용이 높아진다.

  • 용량이 클수록 비트당 비용이 낮아진다.

  • 용량이 클수록 접근 시간이 길어진다.

상위 메모리의 가격이 하위 계층 메모리 대비 비싼 이유

  1. 더 빠른 속도
    캐시 메모리는 SRAM(Static RAM)이라는 기술을 기반으로 만들어지는데, 이는 DRAM(Dynamic RAM)을 사용하는 메인 메모리보다 훨씬 빠릅니다. SRAM은 DRAM처럼 주기적인 새로 고침(refresh)이 필요하지 않아서 더 빠른 데이터 접근이 가능합니다. 빠른 성능을 제공하는 만큼 제조 공정도 더 복잡하고, 이에 따라 비용이 증가합니다.

  2. 복잡한 구조
    SRAM은 DRAM에 비해 복잡한 회로 구조를 가지고 있습니다. DRAM은 하나의 트랜지스터와 하나의 커패시터로 비트를 저장하지만, SRAM은 하나의 비트를 저장하는 데 6개의 트랜지스터를 사용합니다. 이 때문에 같은 용량을 만들기 위해서 훨씬 더 많은 트랜지스터가 필요하며, 그 결과 칩의 크기가 커지고 제조비용이 상승합니다.

  3. 전력 소비
    SRAM은 DRAM보다 더 적은 전력을 소모합니다. 메인 메모리는 데이터 저장을 위해 주기적으로 새로 고침을 해야 하지만, 캐시는 그렇지 않으므로 전력 소모가 적습니다. 이로 인해 효율적인 전력 관리가 가능하지만, 전력 관리 회로의 복잡성도 추가되어 비용이 올라갑니다.

  4. 제조 공정의 복잡성
    캐시 메모리는 메인 메모리에 비해 더 작은 크기로 더 빠른 성능을 제공해야 하기 때문에 고급 제조 공정이 필요합니다. 높은 성능을 유지하면서도 작은 면적에 많은 트랜지스터를 집적해야 하는 기술적 난제가 있으며, 이로 인해 제조 공정이 더 복잡하고 고가의 장비가 필요합니다.

  5. 소량 생산
    메인 메모리(RAM)는 상대적으로 대량 생산되며, 수요도 매우 많아 대규모로 생산됩니다. 그러나 캐시 메모리는 CPU 내부에 내장되며, 상대적으로 소량 생산됩니다. 대량 생산에 의한 단가 절감 효과가 적기 때문에 캐시 메모리의 가격은 더 비싸게 책정됩니다.

  6. 높은 신뢰성 요구
    캐시 메모리는 CPU와 직접 연결되어 즉각적인 데이터 접근을 제공하는 중요한 역할을 하기 때문에 높은 신뢰성이 요구됩니다. 이로 인해 오류 발생을 최소화하기 위한 추가적인 설계와 테스트가 필요하며, 이는 비용 상승의 원인이 됩니다.

저장 장치 간의 성능 차이에는 메모리 자체의 성능 문제도 있겠지만, CPU 차원에서의 소프트웨어적인 주소 처리 문제나 부품의 설계 자체에 의한 물리적 거리 문제도 있다. 이것이 모든 문제의 근원이다.

빠르고 큰 저장 장치는 비싸다는 것은 컴퓨터라는 개념 자체가 정립된 이래로 항상 발생한 문제점이기에, 컴퓨터 공학자들은 싸고 빠른 컴퓨터를 만들 수 있는 방법을 연구하기 시작했다.

그래서 1990년대에 들어서 레지스터-L1캐시-DRAM-HDD-플로피 디스크 정도의 메모리 계층 구조가 정립되었다. 그러나, 각 계층별 격차가 매우 크고 특히 L1 캐시 - DRAM과 DRAM - HDD 사이의 간극이 어마무시했던 관계로, 이로 인한 성능 최적화 한계를 극복하기 위해 메모리 계층 구조는 점점 더 복잡해져왔다.

메모리 용량(Density)과 반도체 제품의 원가(Cost)는 어떠한 상관관계가 있는 걸까? (SK 하이닉스 글 발췌)

  • 제품의 용량이 확대되면 제품의 가격도 상승합니다. 하지만 가격 상승폭 대비 용량성 확대가 더 크기 때문에 가격이 1.5배 상승해도 용량이 보통 4배(2~4배) 정도 증가하므로 수요자는 2.5배 이상의 이익을 얻게 됩니다.
  • 즉, 반도체는 신제품이 출시돼 높은 판매가격으로 형성되어도, 용량이 가격 상승폭 이상으로 늘어나면서 수요자에게 유리하게 되며, 비트당 가격이 더 낮게 형성되어 공급자에게도 유리한 구조가 됩니다.

https://news.skhynix.co.kr/post/memory-semiconductor-capacity

메모리의 지역성(Cache Locality)이란?

캐시메모리의 역할을 제대로 수행하기 위해서는 CPU가 어떤 데이터를 원할 것인가를 어느 정도 예측할 수 있어야 한다. 캐시의 성능은 캐시 메모리에 CPU가 이후에 참조할, 쓸모 있는 정보가 어느 정도 들어있느냐에 따라 좌우되기 때문이다.

이 때 적중율(Hit rate)를 극대화 시키기 위해 데이터 지역성(Locality)를 사용한다.
지역성의 전제조건으로 프로그램은 모든 코드나 데이터를 균등하게 Access 하지 않는다는 특성을 기본으로 한다.
즉, Locality란 기억 장치 내의 정보를 균일하게 Access 하는 것이 아닌 어느 한 순간에 특정 부분을 집중적으로 참조하는 특성인 것이다.

  • 캐시 적중(Cache Hit) : CPU가 액세스하려는 데이터가 이미 캐시에 적재되어있는 상태.
  • 캐시 미스(Cache Miss) : CPU가 액세스하려는 데이터가 캐시에 없어 주기억장치로부터 인출해 와야하는 상태.
  • 캐시 적중률(Cache Hit rate) : CPU가 원하는 데이터가 캐시에 있을 확률.
  • 캐시에 적중되는 횟수 / 전체 기억장치 액세스 횟수
  • 미스율(Miss rate) : CPU가 원하는 데이터가 캐시에 없을 확률, 1-(Cache Hit rate)

문서 처리하는 회사원과 문서 창고를 비유로 들어 설명한 메모리 계층 구조의 개념

https://luv-n-interest.tistory.com/1114

지역성의 종류

데이터 지역성은 대표적으로 시간적 지역성(Tempora Locality)과 공간지역(Spatial Locality)로 나뉜다.

시간적 지역성(Temporal Locality)

시간적 지역성은 최근에 참조된 주소의 내용은 곧 다음에 다시 참조되는 특성이다.

메모리 상의 같은 주소에 여러 차례 읽기 쓰기를 수행할 경우, 상대적으로 작은 크기의 캐시를 사용해도 효율성을 꾀할 수 있다.

공간적 지역성(Spatial Locality)

공간적 지역성은 기억장치 내에 서로 인접하여 저장되어 있는 데이터들이 연속적으로 액세스 될 가능성이 높아지는 특성이다.

CPU 캐시나 디스크 캐시의 경우 한 메모리 주소에 접근할 때 그 주소뿐 아니라 해당 블록을 전부 캐시에 가져오게 된다.

이때 메모리 주소를 오름차순이나 내림차순으로 접근한다면, 캐시에 이미 저장된 같은 블록의 데이터를 접근하게 되므로 캐시의 효율성이 크게 향상된다.

지역성의 특성을 고려하여,
CPU의 캐시에 넣을 때 데이터 지역성을 높일 수 있도록 데이터를 처리하는 순서대로 연속된 메모리에 두면 효율을 높일 수 있다.

1.7 운영체제는 하드웨어를 관리한다

응용프로그램이 하드웨어를 제어하려면 언제나 운영체제를 통해야 한다.

운영체제(Operating System, OS)는 아래 2가지 주요 목적을 지닌다.

  1. 응용프로그램이 제멋대로 동작하며 하드웨어를 오사용 하는 것을 방지
  2. 응용프로그램이 단순하고 통일된 매커니즘을 사용하여, 복잡하고 매우 다른 low-level 하드웨어 장치들을 조작할 수 있도록 하기 위해

운영체제는 위와 같은 목적 달성을 위해 '추상화' 개념을 도입해 사용중.

추상화는 하드웨어의 복잡한 동작을 감추고, 프로그램이 단순한 인터페이스를 통해 하드웨어를 사용할 수 있게 해줍니다.

  • 프로세스
    (프로세서, 메인 메모리, 입출력장치 모두의 추상화 결과)
  • 가상메모리
    (메인 메모리와 디스크 입출력 장치의 추상화)
  • 파일
    (입출력장치의 추상화)

1. 프로세스 (Process)

  • 컴퓨터 구조 관점에서
    프로세스는 실행 중인 프로그램을 의미하며, CPU(프로세서), 메인 메모리, 입출력 장치 등의 하드웨어 자원들을 추상화한 결과입니다. CPU는 여러 응용 프로그램을 동시에 처리할 수 없기 때문에, 운영체제가 각 프로그램을 프로세스라는 단위로 나누어 순차적으로 처리합니다.

    • 멀티태스킹: 운영체제는 각 프로세스가 독립적으로 실행되는 것처럼 보이게 하지만, 실제로는 CPU가 빠르게 프로세스를 전환(Scheduling)하여 동작합니다. 이렇게 여러 프로세스를 동시에 처리하는 것처럼 보이게 하는 것이 멀티태스킹입니다.
    • 프로세스 상태: 프로세스는 실행 상태(Running), 대기 상태(Waiting), 준비 상태(Ready) 등의 상태를 가지고, 운영체제는 프로세스의 상태를 관리하여 효율적으로 CPU를 분배합니다.
  • 예시
    여러 응용 프로그램이 동시에 실행되는 환경에서, 웹 브라우저, 텍스트 에디터, 음악 플레이어 등의 프로그램이 각각 하나의 프로세스입니다. 운영체제는 CPU를 적절히 나누어 이 프로세스들이 끊임없이 동작하도록 합니다.

    • Context Switching: 프로세서가 한 프로세스에서 다른 프로세스로 전환할 때, 현재 프로세스의 상태(레지스터 값, 메모리 상태 등)를 저장하고 새로운 프로세스의 상태를 불러오는 작업을 말합니다. 이 과정이 빠르게 이루어져야 성능이 좋습니다.
    • 추상화의 역할: 프로세스 개념을 통해 각 응용 프로그램은 CPU, 메모리, I/O 장치 등 하드웨어 자원을 직접 제어하지 않고도 운영체제를 통해 안전하게 사용할 수 있습니다.

2. 쓰레드 (Thread)

  • 쓰레드는 프로세스 내에서 실행되는 작은 단위의 작업입니다.
    한 프로세스는 여러 개의 쓰레드를 가질 수 있으며, 이 쓰레드들은 동일한 메모리 공간을 공유하면서 동시에 작업을 수행할 수 있습니다. 쓰레드는 CPU를 효율적으로 사용하여 프로그램의 성능을 높이고, 병렬 처리를 가능하게 합니다. 쓰레드는 프로세스보다 더 가벼운 작업 단위로 간주되며, 경량 프로세스(Lightweight Process)라고도 불립니다.

  • 컴퓨터 구조적인 설명

    • 쓰레드의 개념

      • 쓰레드는 프로세스 내에서 실행되는 독립적인 작업 흐름입니다. 한 프로세스는 하나 이상의 쓰레드를 가질 수 있으며, 각 쓰레드는 독립적으로 실행됩니다.
      • 쓰레드는 프로세스의 자원(메모리, 파일 등)을 공유하지만, 각 쓰레드는 자신만의 스택(Stack)과 레지스터를 가지고 있습니다.
      • 쓰레드는 컨텍스트 스위칭(Context Switching) 없이 빠르게 전환될 수 있어, 병렬 작업을 수행할 때 성능을 크게 향상시킬 수 있습니다.
    • 멀티스레드와 병렬 처리

      • 멀티스레드(Multithreading)는 한 프로세스 내에서 여러 쓰레드가 동시에 실행되는 방식입니다. 이 방식은 CPU 코어의 수가 많을수록 더 많은 쓰레드를 동시에 실행할 수 있어, CPU 자원을 효율적으로 사용하게 됩니다.
      • 병렬 처리(Parallel Processing)는 여러 코어가 각각 다른 쓰레드를 동시에 처리하는 방식으로, 프로그램의 성능을 극대화할 수 있습니다.
    • 쓰레드의 상태

      • 실행 상태(Running): 쓰레드가 실제로 실행 중인 상태.
      • 대기 상태(Waiting): 특정 이벤트가 발생하기를 기다리고 있는 상태.
      • 준비 상태(Ready): 실행할 준비가 되었으나, CPU가 할당되지 않은 상태.
    • 쓰레드의 관리

      • 운영체제는 쓰레드를 생성, 스케줄링, 종료하는 역할을 합니다. 또한, 쓰레드 간의 작업을 조율하고 자원을 할당하는 등 쓰레드 관리를 수행합니다.

멀티 프로세스와 멀티 쓰레드의 차이

  • 멀티 프로세스와 멀티 쓰레드는 모두 동시 작업을 처리하기 위한 방식이지만, 각 방식의 동작 원리와 자원 관리 방법이 다릅니다. 두 방법 모두 컨텍스트 스위칭을 통해 연속적인 작업을 수행할 수 있지만, 성능과 효율성 측면에서 큰 차이가 있습니다.

    • 기본 개념
      • 멀티 프로세스: 여러 프로세스(독립된 프로그램)들이 동시에 실행되는 방식입니다. 각 프로세스는 고유의 메모리 공간을 가지며, 서로 독립적으로 실행됩니다.
      • 멀티 쓰레드: 하나의 프로세스 내에서 여러 쓰레드(작업 단위)가 동시에 실행되는 방식입니다. 같은 프로세스 내의 쓰레드들은 메모리와 자원을 공유하며 실행됩니다.

멀티 프로세스와 멀티 쓰레드의 장단점

  • 멀티 프로세스의 장점:
    • 안정성: 각 프로세스가 독립적이므로, 한 프로세스에서 오류가 발생하더라도 다른 프로세스에는 영향을 미치지 않습니다. 이로 인해 안정성이 높습니다.
    • 보안성: 서로 다른 프로세스는 자원을 공유하지 않기 때문에, 보안이 중요한 상황에서 데이터 보호가 용이합니다.
  • 멀티 프로세스의 단점:
    • 비용: 프로세스 간의 컨텍스트 스위칭 비용이 크고, 프로세스 간 통신(IPC)이 상대적으로 복잡하며 비용이 큽니다.
    • 자원 낭비: 프로세스가 각기 독립된 메모리 공간을 사용하기 때문에, 메모리 자원을 효율적으로 활용하기 어렵습니다.
  • 멀티 쓰레드의 장점:
    • 성능: 쓰레드는 메모리와 자원을 공유하므로, 컨텍스트 스위칭 비용이 적고, 메모리 사용이 효율적입니다. 특히 동일한 데이터나 자원을 사용하는 작업에서 매우 효과적입니다.
    • 응답성: I/O 작업과 CPU 바운드 작업을 병행 처리할 수 있어 프로그램의 응답성이 크게 향상됩니다. 특히 UI 프로그램에서 사용됩니다.
  • 멀티 쓰레드의 단점:
    • 안정성 문제: 쓰레드들이 같은 메모리 공간을 공유하기 때문에, 동기화 문제가 발생할 수 있습니다. 하나의 쓰레드에서 오류가 발생하면 프로세스 전체가 중단될 수 있습니다.
    • 동기화 비용: 쓰레드 간의 자원 접근 시 데이터 동기화(뮤텍스, 세마포어 등)가 필요하며, 이를 잘못 처리할 경우 데드락(교착 상태)이나 경쟁 상태 등의 문제가 발생할 수 있습니다.

멀티 프로세스 vs 멀티 쓰레드 선택 기준

  • 멀티 프로세스가 적합한 경우:

    • 독립적인 작업이 필요한 경우. 예를 들어, 각 작업이 서로 독립적으로 실행되어야 하며, 작업 간 충돌이나 자원 공유가 필요하지 않은 경우.

      • 예시: 웹 브라우저의 각 탭은 서로 독립된 프로세스로 실행됩니다. 하나의 탭에서 오류나 충돌이 발생해도, 다른 탭이나 브라우저 전체에 영향을 미치지 않습니다. 이 방식은 안정성을 높이고, 각 프로세스가 독립적으로 종료되거나 재시작될 수 있도록 합니다.
    • 안정성이 중요한 경우. 프로세스 간에 서로 영향을 미치지 않도록 해야 할 때, 멀티 프로세스가 더 안전합니다.

      • 예시: 서버 애플리케이션에서 각 클라이언트 요청을 별도의 프로세스로 처리할 수 있습니다. 이렇게 하면 하나의 클라이언트 프로세스에서 오류가 발생해도 다른 클라이언트 프로세스에는 영향을 미치지 않으며, 서버의 핵심 프로세스는 안전하게 실행됩니다.
    • 보안이 중요한 시스템에서 서로 다른 프로세스 간에 데이터 보호가 필요할 때.

      • 예시: 서버 애플리케이션에서 각 클라이언트 요청을 별도의 프로세스로 처리할 수 있습니다. 이렇게 하면 하나의 클라이언트 프로세스에서 오류가 발생해도 다른 클라이언트 프로세스에는 영향을 미치지 않으며, 서버의 핵심 프로세스는 안전하게 실행됩니다.
  • 멀티 쓰레드가 적합한 경우:

    • 자원 공유가 필요한 작업이 있을 때. 같은 메모리 공간을 사용하는 여러 작업이 빠르게 데이터를 주고받을 때 멀티 쓰레드가 적합합니다.

      • 예시: 게임 엔진은 렌더링, 물리 엔진, 입력 처리 등 다양한 작업을 병행 처리하는데, 이때 각 쓰레드는 메모리와 자원을 공유하면서 서로 협력합니다. 예를 들어, 렌더링 쓰레드는 게임 화면을 그리는 동안 물리 엔진 쓰레드는 객체 간 충돌을 계산하고, 입력 처리 쓰레드는 사용자 입력을 처리합니다. 이렇게 쓰레드 간 자원을 공유하면 메모리 사용이 효율적이고 성능이 향상됩니다.
    • 컨텍스트 스위칭 비용이 중요한 경우. 자주 스위칭이 필요한 작업에서는 멀티 쓰레드가 더 효율적입니다.

      • 예시: 웹 서버에서 하나의 프로세스 내에서 여러 쓰레드가 동시에 네트워크 요청을 처리하는 경우, 각 쓰레드가 동일한 메모리 공간을 공유하기 때문에 프로세스 간 전환보다 컨텍스트 스위칭 비용이 적습니다. 이로 인해 네트워크 요청을 더 빠르게 처리할 수 있습니다.
    • I/O 작업과 CPU 작업을 동시에 처리해야 할 때. 예를 들어, 네트워크 통신과 데이터 처리 작업을 동시에 진행할 때.

      • 예시: 웹 서버는 네트워크 통신과 데이터베이스 쿼리, 사용자 요청 처리를 동시에 처리해야 합니다. 각 요청을 별도의 쓰레드에서 처리함으로써 네트워크 대기 시간이 길어지더라도 CPU 자원을 효율적으로 사용하고 다른 작업을 처리할 수 있습니다.

3. 가상 메모리 (Virtual Memory)

  • 가상 메모리는 실제 물리적 메모리(RAM)와 상관없이, 운영체제가 프로세스마다 독립적인 메모리 공간을 제공하는 기술입니다. 이를 통해 모든 프로그램이 자신만의 고유한 메모리 공간을 가진 것처럼 동작할 수 있으며, 실제 메모리가 부족할 경우 하드디스크의 일부를 가상 메모리로 사용해 물리 메모리 용량을 확장할 수도 있습니다.

  • 가상 메모리 구조의 주요 구성 요소

    • 프로그램 코드 (Text Section)

      • 역할: 프로그램의 실행 코드가 저장되는 부분입니다. 여기에는 프로그램이 실행할 명령어들이 포함되어 있습니다. 이 영역은 읽기 전용으로 처리되며, 실행 중인 프로세스의 여러 인스턴스가 이 메모리 공간을 공유할 수 있습니다.
      • 특징: 읽기 전용(Read-Only)으로 설정되어 있어, 코드의 변경이 불가능합니다. 따라서 여러 프로세스가 동시에 실행되더라도 동일한 코드 섹션을 공유할 수 있습니다.
      • 예시: 컴파일된 프로그램의 기계어 명령들이 이 영역에 포함됩니다.
    • 데이터 (Data Section)

      • 역할: 프로그램이 정적 데이터를 저장하는 공간입니다. 전역 변수나 초기화된 변수(global, static)가 이 공간에 저장됩니다.
      • 특징: 프로그램이 실행되는 동안 메모리 내에 상주하며, 읽기 및 쓰기가 가능합니다. 다른 섹션에 비해 수정이 자주 일어나므로, 프로그램의 실행 중 이 영역의 내용이 계속해서 변경될 수 있습니다.
      • 예시: int globalVar = 10;와 같은 전역 변수는 이 데이터 영역에 저장됩니다.
    • 힙 (Heap)

      • 역할: 동적으로 할당된 메모리가 저장되는 영역으로, 런타임 중에 필요한 메모리 공간을 동적으로 할당 및 해제할 수 있습니다. 프로그램이 실행되면서 동적 할당된 데이터가 이 힙 영역에 저장됩니다.
      • 특징: 힙은 하향 확장됩니다(메모리 주소가 큰 쪽으로 확장). 동적 메모리 할당 시 malloc, new와 같은 함수가 사용되며, 사용 후 메모리 해제를 위해 free, delete를 사용합니다. 힙 관리를 잘못하면 메모리 누수나 비효율적 메모리 사용이 발생할 수 있습니다.
      • 예시: int ptr = (int)malloc(sizeof(int));는 힙 영역에 메모리를 할당합니다.
    • 공유 라이브러리 (Shared Libraries)

      • 역할: 공유 라이브러리는 여러 프로그램이 공통으로 사용하는 함수와 데이터들이 포함된 메모리 영역입니다. 이 영역에는 동적 라이브러리(.so 파일 또는 .dll 파일)와 같은 공유 자원이 포함됩니다.
      • 특징: 여러 프로세스가 동일한 라이브러리를 사용하더라도, 메모리 상에서 하나의 공유 라이브러리를 참조할 수 있습니다. 이를 통해 메모리 사용량을 줄이고 프로그램 실행을 효율적으로 할 수 있습니다.
      • 예시: 표준 C 라이브러리 함수들(예: printf)은 메모리 내에서 공유 라이브러리로 로드됩니다.
    • 스택 (Stack)

      • 역할: 함수 호출 시 지역 변수와 함수 호출 기록(복귀 주소, 매개변수, 반환값 등)이 저장되는 영역입니다. 함수가 호출될 때마다 스택 프레임이 추가되고, 함수가 종료되면 스택에서 해당 프레임이 제거됩니다.

      • 특징: 스택은 상향 확장됩니다(메모리 주소가 작은 쪽으로 확장). 스택은 LIFO(Last In First Out) 구조를 따르며, 함수가 호출될 때마다 스택 프레임이 추가되고, 함수가 종료되면 해당 프레임이 제거됩니다. 스택의 크기가 너무 커질 경우 스택 오버플로우가 발생할 수 있습니다.

      • 예시: int localVar;와 같은 함수 내부에서 선언된 지역 변수는 스택에 저장됩니다.

    • 커널 가상 메모리 (Kernel Virtual Memory)

      • 역할: 운영체제 커널이 사용하는 메모리 영역입니다. 사용자 프로세스가 직접 접근할 수 없는 보호된 메모리 공간으로, 시스템 호출이 발생할 때 커널이 해당 영역에 접근합니다.

      • 특징: 이 영역은 운영체제 전용으로, 메모리 관리, 디바이스 드라이버, 시스템 호출 처리 등과 관련된 중요한 데이터가 저장됩니다. 사용자 프로그램은 직접 이 메모리에 접근할 수 없으며, 커널이 이를 보호합니다.

      • 예시: 운영체제가 사용하는 파일 시스템 정보나 하드웨어 정보 등이 이 공간에 저장됩니다.

  • 가상 메모리의 구조

    • 사용자 공간(User Space):
      일반적으로 사용자 프로세스는 자신이 사용할 메모리 공간만을 가질 수 있는 것으로 보입니다. 하지만, 가상 메모리 시스템에서 사용자 프로세스는 자신의 주소 공간이 물리 메모리에 직접 매핑되지 않고, 필요한 경우에만 실제 메모리로 불러와집니다. 여기서 프로그램 코드, 데이터, 힙, 스택 등의 영역이 포함됩니다.

    • 커널 공간(Kernel Space):
      운영체제는 사용자 프로세스와 독립적인 커널 전용 메모리 공간을 가지고 있으며, 이 공간은 프로세스가 시스템 자원에 접근하거나 요청할 때만 접근할 수 있습니다. 보안과 시스템 안정성을 위해 커널 공간은 보호됩니다.

  • 가상 메모리의 장점

    • 메모리 확장:
      실제 물리 메모리보다 큰 메모리 공간을 사용할 수 있도록 해줍니다. 프로그램이 실제로 사용하는 데이터만 메모리에 적재하여, 효율적인 메모리 사용이 가능합니다.
    • 보안:
      각 프로세스는 자신의 가상 메모리 공간을 사용하므로, 프로세스 간의 메모리 간섭이 발생하지 않습니다.
    • 메모리 보호:
      프로그램이 자신의 가상 메모리 공간에서만 작업할 수 있도록 하여, 다른 프로그램의 메모리 영역을 침범하지 못하게 보호합니다.
    • 메모리 분할:
      물리 메모리와 달리, 가상 메모리는 여러 조각으로 분할되어 사용할 수 있습니다. 이는 다양한 작업을 동시에 처리하는 데 유리합니다.
  • 가상 메모리는 프로그램의 실행 환경을 추상화하고, 물리 메모리와 상관없이 많은 프로그램이 동시에 실행될 수 있도록 지원하는 중요한 기술입니다.

  1. 파일 (File)
  • 컴퓨터 구조 관점에서
    파일은 하드 디스크나 SSD와 같은 저장 장치(I/O 장치)를 추상화한 개념으로, 데이터를 논리적 단위로 관리하는 방법입니다. 물리적으로 저장 장치는 블록 단위로 데이터를 저장하지만, 운영체제는 파일 시스템을 통해 데이터를 파일이라는 논리적 단위로 추상화하여 사용자와 응용 프로그램이 쉽게 데이터를 다룰 수 있도록 합니다.
    운영체제는 파일 시스템을 통해 파일을 관리하며, 디렉터리 구조를 통해 파일을 체계적으로 저장하고 접근할 수 있게 합니다. 파일 시스템은 파일의 읽기, 쓰기, 생성, 삭제 등의 작업을 제공합니다.

  • 예시
    사용자가 작성한 문서 파일이나 음악 파일, 응용 프로그램 설치 파일 등은 모두 파일입니다. 예를 들어, 텍스트 파일을 열면, 운영체제는 물리적인 하드 드라이브에서 파일의 내용을 메모리로 불러오고, 응용 프로그램이 그 데이터를 처리할 수 있게 합니다.

    • 디스크 블록과 파일 매핑: 파일 시스템은 물리 디스크의 블록을 파일로 연결하는 매핑 테이블을 사용하여, 파일이 어디에 저장되어 있는지 관리합니다.
    • 추상화의 역할: 파일 개념을 통해, 응용 프로그램은 복잡한 디스크 입출력 세부 사항을 알 필요 없이, 데이터를 읽고 쓰는 작업을 수행할 수 있습니다. 운영체제는 이러한 파일 접근을 안전하고 효율적으로 처리합니다.
  • 쓰레드
    • 시중에 나와 있는 CPU는 멀티 코어, 멀티 쓰레드로 성능이 표기된다.
    • 앞서 설명한 CPU의 개념은 1개의 코어가 담당하는 업무를 설명한 것과 같다.
    • 코어 1개는 동시간대에 1개의 프로세스의 연산을 진행할 수 있다.
    • 프로세스간 전환의 순간에 잠깐의 공백 등이 생기고 이는 곧 연산의 비효율로 이어진다.
    • 이때 사용 가능한 것이 쓰레드의 개념이다.
    • 코어는 1개의 프로세스의 연산을 담당하지만, 쓰레드는 1개의 프로세스에 여러개의 쓰레드가 개입하여 연산할 수 있다.
    • 코어가 한명의 대장군이라면, 쓰레드는 일종의 작은 병사들로 비유해 볼 수 있다.
    • Intel의 CPU 칩셋의 경우 1개의 코어가 2개의 쓰레드를 부릴 수 있다.
    • 쓰레드의 자세한 설명은 추후 별첨 예정.

쓰레드 보충 설명
https://velog.io/@susuggang/CPU-%EC%BD%94%EC%96%B4%EC%99%80-%EC%93%B0%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4

1.8 시스템은 네트워크를 통해 다른 시스템과 통신한다

네트워크는 컴퓨터가 외부와 통신할 수 있게 해주는 통로로서, 데이터를 입력받고 출력하는 역할을 합니다. 이를 통해 네트워크는 하드디스크, 키보드, 모니터와 같은 다른 입출력 장치와 비슷하게 동작합니다. 다음은 네트워크가 입출력 장치로서 작동하는 방식에 대한 설명입니다:

1. 네트워크의 입력 역할
네트워크를 통해 다른 시스템에서 데이터가 컴퓨터로 전송됩니다.
예를 들어, 사용자가 웹사이트를 요청하면 클라이언트는 서버에 요청을 보내고, 서버는 해당 웹페이지 데이터를 네트워크를 통해 클라이언트로 전송합니다. 이 데이터는 네트워크에서 입력되는 형태로, 웹 브라우저와 같은 프로그램에서 처리됩니다.

예시:
웹 브라우저에서 사용자가 URL을 입력하면, 서버로부터 웹 페이지가 로드되어 데이터가 입력됩니다.
이메일 클라이언트가 서버로부터 새로운 이메일 데이터를 수신할 때 네트워크로부터 데이터가 컴퓨터로 입력됩니다.

2. 네트워크의 출력 역할
반대로, 컴퓨터는 네트워크를 통해 다른 시스템으로 데이터를 전송할 수 있습니다.
예를 들어, 사용자가 전자 메일을 작성하여 보내면, 메일 클라이언트는 이 데이터를 네트워크를 통해 메일 서버로 출력합니다. 이 과정은 데이터를 외부 장치로 보내는 것과 유사합니다.

예시:
사용자가 이메일을 보낼 때, 작성된 이메일은 네트워크를 통해 서버로 출력됩니다.
파일 업로드 시, 로컬에서 네트워크를 통해 원격 서버로 파일이 출력됩니다.

1.9 컴퓨터 시스템 분야의 중요한 개념들

  • Amdahl의 법칙
    Amdahl의 법칙은 시스템 성능 개선을 위한 병렬화의 한계를 설명하는 법칙입니다. 병렬화를 통해 성능을 향상시킬 수 있지만, 프로그램의 전체 성능은 병렬화할 수 없는 부분에 의해 제한됩니다.

  • 여기서,
    S는 성능 향상 배수,
    P는 병렬화 가능한 부분의 비율,
    N은 병렬로 처리할 수 있는 프로세서 수입니다.

    • 핵심은 프로그램의 일부만 병렬화할 수 있다면, 그 병렬화가 가능한 부분이 아무리 많아도 병렬화할 수 없는 부분 때문에 성능 향상에 한계가 있다는 것입니다.

    • 예시:
      만약 프로그램의 90%가 병렬화 가능하고 10%는 병렬화 불가능하다면, 아무리 많은 프로세서가 있어도 성능 향상은 10배로 제한됩니다.

  • 동시성과 병렬성

    • 동시성(Concurrency):
      여러 작업이 동시에 실행되는 것처럼 보이는 개념입니다. 실제로는 하나의 CPU 코어가 작업을 빠르게 전환하는 방식으로 처리합니다.

    • 병렬성(Parallelism):
      여러 작업이 물리적으로 동시에 실행되는 것을 의미합니다. 여러 CPU 코어나 프로세서를 사용하여 병렬로 작업을 수행합니다.

    • 쓰레드 수준 동시성(Thread-Level Concurrency):
      하나의 프로그램 내에서 여러 쓰레드가 동시에 실행되는 것처럼 보이는 방식입니다. 쓰레드는 같은 프로세스의 자원을 공유하면서 병렬로 실행될 수 있습니다.
      멀티스레딩을 사용하여 프로그램의 성능을 향상시키며, CPU 코어가 많을수록 더 많은 쓰레드를 동시에 처리할 수 있습니다.

    • 인스트럭션 수준 병렬성(Instruction-Level Parallelism, ILP):
      프로세서가 하나의 명령어 흐름에서 여러 명령어를 동시에 실행할 수 있는 능력입니다. 파이프라이닝이나 슈퍼스칼라 구조와 같은 기술을 통해 인스트럭션을 병렬로 처리합니다.
      여러 명령어를 동시에 실행하여 CPU의 성능을 최대한 활용하는 방법입니다.

    • 싱글 인스트럭션, 다중 데이터 병렬성(Single Instruction, Multiple Data, SIMD):
      하나의 명령어가 동시에 여러 데이터에 대해 동일한 연산을 수행하는 방식입니다. 벡터 프로세싱 또는 GPU에서 많이 사용됩니다.
      예시:
      이미지 처리에서 하나의 필터 연산이 여러 픽셀에 동시에 적용되는 경우가 이에 해당합니다.

  • 컴퓨터 시스템에서 추상화의 중요성
    • 추상화(Abstraction)는 복잡한 시스템을 단순화하여 상위 수준의 작업을 쉽게 처리할 수 있게 하는 개념입니다. 컴퓨터 시스템에서는 하드웨어의 복잡성을 숨기고, 프로그래머가 간단한 인터페이스로 시스템 자원을 사용할 수 있게 합니다.
    • 예시:
      • 메모리 추상화: 프로그래머는 메모리 주소를 직접 관리할 필요 없이, 가상 메모리 개념을 통해 편리하게 메모리를 사용할 수 있습니다.
      • 파일 시스템 추상화: 물리적인 저장 장치를 직접 다루지 않고, 운영체제가 제공하는 파일 시스템 인터페이스를 사용하여 파일을 처리합니다.
    • 추상화는 컴퓨터 시스템의 설계를 간단하게 하고, 다양한 하드웨어와 소프트웨어 간의 상호작용을 쉽게 만듭니다.
profile
juniorDev

0개의 댓글