[TIL/크래프톤 정글9기] 5일차(컴퓨터시스템)

blueprint·2025년 5월 16일

크래프톤정글9기

목록 보기
6/55

컴퓨터 시스템

이번주 미니프로젝트를 끝내고 조가 바뀌고 WEEK00에서 넘어가면서 WEEL01 컴퓨팅사고로의전환이 주제다.

WEEK01은 알고리즘 문제 풀기와 컴퓨터시스템 책에 대한 내용을 공부해야한다.

처음 본 팀원분들과 각자 컴퓨터시스템으로의 여행 1 챕터를 읽고 읽고 모르는 내용을 서로 공유하고 내용을 정리해 보겠다.

1.1 정보는 비트와 컨택스트로 이루어진다

  1. 모든 정보는 비트의 연속이다
    hello.c 프로그램처럼, 프로그래머가 작성한 소스 코드는 비트(0과 1)의 연속으로 저장
    이 비트들은 8비트 단위인 바이트(byte)로 구성되며, 각 바이트는 하나의 문자를 나타냄

  2. 아스키(ASCII)를 통한 문자 표현
    대부분의 시스템은 문자를 아스키 코드로 표현
    이렇게 저장된 파일을 텍스트 파일이라 부르고, 아스키 문자가 아닌 데이터는 바이너리 파일이라 부름

  3. 컨텍스트(Context)의 중요성
    동일한 비트/바이트라도 어떤 컨텍스트로 해석하느냐에 따라 의미가 완전히 달라짐
    예: 같은 비트열이 문자, 정수, 실수, 기계어 명령 등으로 해석될 수 있음
    즉, 비트 + 컨텍스트 = 의미 있는 정보

  4. 숫자 표현의 한계
    컴퓨터의 숫자 표현(정수, 실수)은 유한한 비트로 근사된 값이기 때문에, 우리가 기대한 대로 동작하지 않을 수 있음

1.2 프로그램은 다른 프로그램에 의해 다른 형태로 변역된다

  1. 전처리 단계 (Preprocessing)
    #로 시작하는 전처리 지시문 처리
    #include → 헤더 파일 내용을 코드에 삽입
    #define → 매크로 치환

주석 제거

결과물: 전처리된 C 코드 → hello.i

  1. 컴파일 단계 (Compilation)
    역할: C 코드를 어셈블리어로 번역
    문법 검사, 변수 → 레지스터 할당, 조건문/루프 → 점프 등
    결과물: 어셈블리 코드 → hello.s

  2. 어셈블리 단계 (Assembly)
    역할: 어셈블리어를 기계어(목적 코드)로 변환
    CPU가 직접 실행할 수 있는 이진 명령어로 구성
    결과물: 목적 파일(Object file) → hello.o

  3. 링크 단계 (Linking)
    역할: 여러 개의 목적 파일과 라이브러리 함수를 연결해 하나의 실행파일 생성
    예: printf는 hello.c에 없고, 표준 라이브러리에 있음 → 링크 시 결합
    결과물: 실행 가능한 바이너리 파일 → hello

1.3 컴파일 시스템이 어떻게 동작하는지 이해하는 것은 중요하다

프로그램 성능 최적화
컴파일러는 우수한 기계어 코드를 생성하지만, 프로그래머가 성능 최적화를 하려면 기계어 수준의 이해가 필요함.

링크 에러 이해
이런 질문을 이해해야 함:
"참조를 풀 수 없다"는 무슨 뜻?
정적 변수 vs 전역 변수?
동일한 이름의 전역 변수가 두 파일에 존재하면?
정적/동적 라이브러리 차이?
컴파일 시 라이브러리 순서가 왜 중요?
왜 링크 에러는 실행 전까지도 안 나올 수 있는가?

보안 약점 피하기
버퍼 오버플로우는 대표적인 보안 취약점
스택 구조와 메모리 저장 방식을 이해해야 보안에 강한 코드를 작성할 수 있음
이 취약점은 신뢰할 수 없는 데이터의 크기나 형식을 체크하지 않아서 생김
안전한 프로그래밍을 위해 어셈블리 수준의 이해도 중요

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

1.4.1 시스템의 하드웨어 조직


버스(Buses)

  • 컴포넌트 간에 바이트 정보들을 전송
  • 버스는 워드(word)라고 하는 고정 크기의 바이트 단위로 데이터를 전송

입출력 장치(I/O Devide)

  • 입출력 장치는 컴퓨터와 외부의 입출력 연결을 담당
  • 키보드, 마우스, 디스플레이, 메모리 디스크 등

메인 메모리(Main Memory)

  • 프로세서가 프로그램을 실행하는 동안 데이터와 프로그램을 모두 저장하는 임시 저장장치
  • 물리적으로 DRAM으로 구성
  • 논리적으로는 연속적인 바이트의 배열로, 각각 0부터 시작해서 고유의 주소(배열의 인덱스)를 가짐

프로세서(주처리장치, CPU)

  • 메인 메모리에 저장된 인스트럭션을 해독(실행)하는 엔진
  • 프로세서의 중심에는 PC(프로그램 카운터)가 존재

레지스터(Register)

  • CPU 내에서 자료를 보관하는 아주 빠른 저장소
  • 일반적으로 계산을 수행중인 값을 저장

프로그램 카운터(PC, Program Counter)

  • CPU 내부에 있는 레지스터 중의 하나
  • 다음에 실행될 명령어의 주소를 가지고 있어 실행할 기계어 코드의 위치를 지정
  • 시스템에 전원이 공급되는 순간부터 전원이 끊어질 때 까지 프로세서는 프로그램 카운터가 가르키는 곳의 인스트럭션을 반복적으로 실행하고 프로그램 카운터 값이 다음 인스트럭션을 가리키도록 업데이트

수식/논리 처리기(ALU, Arithmetic logic unit)

  • 산술연산과 논리연산을 계산하는 디지털 회로

CPU가 실행하는 단순한 작업 예

  • 적재(Load): 메인 메모리에서 레지스터에 한 바이트 또는 워드를 이전 값에 덮어쓰는 방식으로 복사
  • 저장(Store): 레지스터에서 메인 메모리로 한 바이트 또는 ㅜ어드르 이전 값을 덮어쓰는 방식
  • 작업(Operate): 두 레지스터의 값을 ALU로 복사하고 두 개의 워드로 수식연산을 수행한 뒤, 결과를 덮어쓰기 방식으로 레지스터에 저장
  • 점프(Jump): 인스트럭션 자신으로부터 한 개의 워드를 추출하고, 이것을 PC에 덮어쓰 쓰기 방식으로 복사

1.4.2 hello 프로그램 실행


1. 쉘프로그램에 ./hello를 입력하면, 쉘 프로그램은 각각의 문자를 레지스터에 읽어들인 후 메모리에 저장

2. 키보드에서 엔터(Enter)를 누르면 쉘은 명령 입력을 끝난걸로 앎. 그러면 쉘은 파일 내의 코드와 데이터를 복사하는 일련의 인스트럭션을 실행하여 실행파일 hello를 디스크에서 메인 메모리로 로딩. 직접 메모리 접근기법(DMA)을 이용하여 데이터는 프로세서를 거치지 않고 디스크에서 메인 메모리로 직접 이동

3. hello의 목적파일의 코드와 데이터가 메모리에 적재된 후, 프로세서는 hello프로그램의 main 루틴의 기계어 인스트럭션을 실행하기 시작. 이 인스트럭션들은 hello, world\n를 메모리로부터 레지스터 파일로 복사하고, 거기로부터 디스플레이 장치로 전송하여 화면에 출력

1.5 캐시가 중요하다

  1. 프로그램은 정보를 계속 '복사'하며 실행
  • 실행 전: 하드디스크 → 메모리
  • 실행 중: 메모리 → CPU
  • 출력 시: 메모리 → 디스플레이
  • 이런 복사 작업들은 실제 연산이 아니라 오버헤드이며 속도를 느리게 함
  1. 하드웨어 저장장치는 빠를수록 작고 비쌈
  • 저장장치 속도 계층(느림 → 빠름):
    디스크 < 메모리 < 캐시 < 레지스터

  • 예시:

    • 디스크는 메모리보다 크지만 최대 1천만 배 느림
    • 레지스터는 메모리보다 100배 빠름
  • 문제: 프로세서 속도는 빨라지는데 메모리는 상대적으로 느림 → 속도 격차 발생

  1. 해결책: 캐시 메모리
  • CPU와 메모리 사이에 위치하는 작고 빠른 저장소
  • CPU가 자주 쓸 데이터를 미리 저장해두고 빠르게 접근함
  • 종류:
    • L1 캐시: 아주 작고 빠름 (수천 바이트)
    • L2 캐시: 좀 더 큼, L1보다 느림 (수백 KB~수 MB)
    • L3 캐시: 최신 시스템에서 사용됨
  1. 캐시의 핵심 원리: 지역성(Locality)
    프로그램은 같은 데이터나 근처의 코드를 반복적으로 사용함
    이 성질을 활용해 캐시에 저장해두면 CPU가 느린 메모리에 접근하는 빈도 줄일 수 있음

  2. 결론
    응용 프로그래머가 캐시의 개념과 작동 원리를 이해하면,
    프로그램 성능을 최대 10배 이상 개선할 수 있음

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

  1. 캐시는 단순한 아이디어가 아니다 — 보편적인 시스템 설계 원칙
  • 빠르고 작은 저장장치(예: 캐시)를 느리고 큰 저장장치(예: 메모리) 사이에 두는 구조는 모든 컴퓨터 시스템에서 사용됨
  • 저장장치들을 속도, 크기, 비용에 따라 계층적으로 배열함
  1. 각 계층은 그 아래 계층의 캐시 역할
    L1 캐시 → L2 캐시 → L3 캐시 → 메인 메모리 → 디스크 → 네트워크 디스크
  • 위로 갈수록:
    • 빠르고, 작고, 비쌈
  • 아래로 갈수록:
    • 느리고, 크고, 쌈
  1. 메모리 계층 구조에서의 레벨 구분
  • L0: 레지스터 (가장 빠름, 가장 작음)
  • L1: 1차 캐시
  • L2: 2차 캐시
  • L3: 3차 캐시
  • L4: 메인 메모리
  • L5: 로컬 디스크
  • L6: 원격 디스크 (네트워크 서버 등)

예시 구조

프로그래머의 역할
단순히 캐시뿐만 아니라 전체 메모리 계층 구조를 이해하면 데이터를 어디에 두고, 어떻게 접근할지 결정하여 성능을 크게 개선할 수 있음

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


운영체제(OS)는 하드웨어와 응용프로그램 사이의 중재자 역할을 함
응용프로그램은 하드웨어를 직접 제어하지 않고, 운영체제가 제공하는 서비스(시스템 콜 등)를 통해서만 하드웨어에 접근

운영체제의 2가지 주요 목적:

  • 프로그램이 하드웨어를 잘못 사용하지 못하게 보호
  • 프로그램이 복잡한 하드웨어를 단순한 방식으로 다루도록 도와줌 (일관된 인터페이스 제공)
추상화실제 하드웨어
프로세스CPU, 메모리, I/O 장치
가상 메모리실제 메인 메모리 + 디스크
파일디스크, I/O 장치

이 추상화를 통해 응용 프로그램은 하드웨어의 복잡성을 몰라도 되고, 더 안전하고 간편하게 실행될 수 있음

프로세스란?

실행 중인 프로그램에 대한 운영체제의 추상화

  • hello 프로그램처럼, 실행 중인 모든 프로그램은 프로세스가 된다.
  • 각각의 프로세스는 자신만 하드웨어를 쓰는 것처럼 보이도록 운영체제가 관리한다.
  • 하지만 실제로는 한 CPU를 여러 프로세스가 교대로 사용한다 → 이것이 동시성(concurrency)


문맥 전환 (Context Switching)

  • CPU가 다른 프로세스로 제어권을 넘기는 과정
  • 운영체제가 현재 프로세스의 상태(=컨텍스트)를 저장하고, 다음 프로세스의 상태를 복원한 뒤 실행을 이어감

컨텍스트 정보:

  • 프로그램 카운터(PC)
  • 레지스터 값
  • 메모리 상태 등

예시 시나리오: hello 프로그램 실행 과정
1. 쉘(shell) 프로그램이 입력 대기
2. 사용자가 ./hello 입력 → 쉘이 시스템 콜을 통해 운영체제에 제어권 넘김
3. 운영체제:

  • 쉘 프로세스의 컨텍스트 저장
  • hello 프로세스 생성 & 컨텍스트 설정
  • hello 프로세스로 CPU 제어권 넘김
  • hello 실행 완료 → 운영체제가 다시 쉘의 컨텍스트 복원 → 쉘 재개

커널(kernel)이란?

  • 운영체제의 핵심 코드
  • 항상 메모리에 상주하며 모든 시스템 자원을 관리
  • 별도 프로세스가 아님, 모든 프로세스와 함께 동작
  • 응용 프로그램이 시스템 콜을 호출할 때 커널에 제어권이 넘어감

요약 핵심 문장

  • 프로세스는 실행 중인 프로그램의 추상화이며, 운영체제는 문맥 전환을 통해 여러 프로세스를 번갈아 실행함으로써 하나의 CPU로 동시성을 제공
  • 이 모든 과정은 커널을 통해 안전하고 일관되게 관리

1.7.2 쓰레드(Thread)

쓰레드는 프로세스 내부에서 실행되는 하나의 흐름(제어 흐름)

개념

  • 전통적으로 하나의 프로세스 = 하나의 실행 흐름
  • 하지만 현대 시스템에서는 프로세스 내부에 여러 개의 쓰레드가 존재 가능
  • 쓰레드는 코드, 전역 데이터, 힙을 공유하면서 독립적으로 실행됨

쓰레드의 장점

  1. 데이터 공유가 쉬움

    • 같은 프로세스 내 쓰레드끼리는 메모리 공간을 공유하기 때문에, 데이터 교환이 효율적
  2. 효율성

  • 프로세스를 생성/전환하는 것보다 쓰레드를 사용하는 것이 더 가볍고 빠름
  1. 멀티코어 CPU 활용
  • 여러 쓰레드를 병렬로 실행함으로써 성능 향상 가능

1.7.3 가상메모리(Virtual Memory)


가상메모리는 각 프로세스가 메모리를 독점적으로 사용하는 것처럼 보이게 만드는 환상

가상 메모리의 목적
여러 프로세스가 동시에 실행되어도 충돌하지 않도록 보호

각 프로세스에 독립적인 주소 공간 제공 (보안성, 안정성 확보)

가상 주소 공간 구성
1. 프로그램 코드와 전역 데이터

  • 고정된 위치에서 시작, hello 프로그램의 코드 및 전역 변수 저장

2. 힙(Heap)

  • malloc, free를 통해 런타임에 크기가 동적으로 변함

3. 공유 라이브러리

  • 표준 C 라이브러리 등 외부 라이브러리 코드 위치

4. 스택(Stack)

  • 함수 호출 시마다 증가하고, 반환 시 줄어듬

5. 커널 영역

  • 운영체제를 위한 공간, 사용자 프로그램은 접근 불가

작동 방식

  • CPU가 만든 가상 주소는 MMU(메모리 관리 유닛)와 운영체제가 협력해 실제 물리 주소로 변환
  • 실제 메모리는 디스크 기반의 캐시처럼 사용됨

1.7.4 파일(File)

파일은 연속된 바이트이며, 모든 입출력 장치는 파일로 모델링
디스크, 키보드, 디스플레이, 네트워크 등 모든 장치는 파일로 취급
유닉스 시스템에서 모든 입출력은 파일 읽기/쓰기와 같은 시스템 콜을 통해 이루어짐

장점
1. 장치에 대한 추상화

  • 프로그래머는 하드웨어 세부 사항을 몰라도 입출력 가능
  1. 이식성
    • 같은 코드가 다양한 하드웨어에서 실행 가능
개념정의목적/장점
쓰레드프로세스 내 실행 흐름빠르고 가볍게 병렬 처리, 공유 메모리 활용
가상메모리프로세스에 독립된 메모리 환상 제공보호, 안정성, 효율적 메모리 사용
파일연속된 바이트로 구성된 추상화모든 장치 입출력 통일, 장치 독립성 제공

1.8 시스템은 네트워크를 사용하여 다른 시스템과 통신한다

네트워크는 또 다른 입력장치로 볼 수 있음
시스템이 메인 메모리로부터 네트워크 어댑터로 일련의 바이트를 복사할 때, 데이터는 로컬디스크 드라이브 대신에 네트워크를 통해서 다른 컴퓨터로 이동

1.9 중요한 주제들

1.9.1 Amdahl의 법칙

  • 우리가 어떤 시스템의 한 부분의 성능을 개선할 때, 전체 시스템 성능에 대한 효과는 구 부분이 얼마나 중요한가와 이 부분이 얼마나 빨라졌는가에 관계됨

1.9.2 동시성과 병렬성

동시성 : 다수의 동시에 벌어지는 일을 갖는 시스템에 관한 일반적인 개념, 동시에 여러 작업이 진행 중인 것처럼 보임
병렬성 : 동시성을 사용해서 시스템을 보다 더 빠르게 동작하도록 하는 것, 여러 작업이 실제로 동시에 실행

쓰레드 수준 동시성

  • 쓰레드를 이용하면 한 개의 프로세스 내에서 실행되는 다수의 제어흐름을 가질 수 있음
  • 인스트럭션 수준 병렬성
  • 프로세서들은 훨씬 낮은 수준에서의 추상화로 여러 개의 인스트럭션을 한 번에 실행할 수 있음
  • 컴퓨터 시스템에서 추상화의 중요성

0개의 댓글