HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
👻
개발 기록
/
💡
컴퓨터 밑바닥의 이해 퀴즈
💡

컴퓨터 밑바닥의 이해 퀴즈

1장

  1. 다음 중 링커가 하는 일이 아닌 것은? a. 인터페이스 구현이 종속된 모듈에서 사용 가능한지 확인 b. 컴파일러가 생성한 대상 파일 여러 개를 하나로 묶어 하나의 최종 실행 파일을 생성 c. 함수가 어느 메모리 주소에 위치할지 정확히 알 수 없어 N으로 표시한 것들을 실행 파일을 생성하는 과정에서 함수의 정확한 주소를 확인하고, N을 실제 메모리 주소로 대체 d. 지역 변수를 참조하여 대상 정의가 존재하는지, 단 하나만 존재하는지 확인
  1. CPU가 프로그램 A와 프로그램 B를 실행했다. 프로그램 A와 B 모두 동일한 가상 메모리 주소에 접근했을 때, 실제로 명령어를 꺼내는 물리 메모리 주소는 같을까?
정답
  1. d. 지역 변수는 모듈 내에서만 사용되어 외부 모듈에서 참조할 수 없기 때문에 링커의 관심 대상이 아님.
  1. X. 같은 가상 메모리 주소라도 페이지 테이블을 확인하여 서로 다른 물리 메모리 주소를 획득한다. 이런 이유로 CPU는 동일한 가상 메모리 주소에서 서로 다른 내용을 가져올 수 있다.
보관
  1. 인간이 직접 인식할 수 있는 최초의 언어는?
  1. 컴퓨터는 프로그래밍 언어를 처리할 때 구문 정의에 따라 00 형태로 코드를 구성할 수 있습니다.
  1. x86 플랫폼용으로 생성한 실행 파일을 ARM 플랫폼에서 직접 실행할 수 있다.
  1. 컴파일러란?
  1. 프로그래밍 언어의 구문 규칙에 따라 프로그래머가 인간이 인식할 수 있는 단어로 코드를 작성하면 코드는 일반적인 텍스트 파일 형태의 파일로 저장되는데, 이를 00 00이라고 합니다.
  1. 어휘 분석, 구문 분석, 의미 분석이 뭔가요?
  1. 컴파일러가 코드를 기계 명령어로 번역하고, 그 정보를 대상 파일에 담았을 때, 대상 파일에 중요한 두가지 영역으로 코드 영역과 데이터 영역이 있다. 다음 중 전역 변수, 정의된 함수, 로컬 변수는 어디에 저장이 될까? 보너스 질문) 대상 파일에 저장된 또 하나, 심벌 테이블에 대해 설명하세요.
  1. 다음 중 성격이 다른 하나를 고르시오 a. 코드 영역 b. 데이터 영역 c. 심벌 테이블 d. 동적 링크 관련 정보
  1. 동적 라이브러리의 특징을 모두 고르시오. a. 플러그인을 구현할 수 있다. b. 하나의 프로젝트에서 여러 언어를 혼합하여 개발할 수 있다. c. 프로그램 업그레이드와 버그 수정을 쉽게 만들어 준다. d. 정적 링크를 사용할 때보다 성능이 좋다. e. 메모리에 단 하나의 복사본만 존재하고 해당 코드는 여러 프로세스가 공유할 수 있기 때문에 절대 주소를 참조한다.
보관 정답
  1. 어셈블리어
  1. 트리
  1. x
  1. 컴파일러는 고수준 언어를 저수준 언어로 번역하는 프로그램
  1. 소스 파일
  1. 어휘분석 : 소스 코드에서 토큰을 추출하는 과정 구문 분석 : 구문 규칙에 따라 토큰을 해석한 후 생성된 구문 트리의 전체 과정 의미 분석 : 구문 트리에 이상이 없는지 확인하고 컴파일 오류가 없다는 것을 증명하는 과정
  1. 명령어 부분 : 정의된 함수 데이터 부분 : 전역 변수 로컬 변수는 프로그램이 실행된 후 스택 영역에서 사용되고 사용하면 제거되기 때문에 대상 파일에는 별도로 저장되지 않음. 보너스 질문) 컴파일러가 외부 심벌 정보를 기록하는 표. 여기서 심벌은 전역 변수와 함수의 이름을 포함하는 모든 변수 이름을 의미.
  1. d. 실행 파일에 들어있는 정보. 나머지는 둘다 존재함. 대상 파일은 주로 정적 링크를 위한 정보를 포함하고, 실행 파일은 동적 링크와 관련된 추가 정보를 포함하여 실행 가능한 형태로 만들어집니다.
  1. a, b, c d: 동적 라이브러리는 프로그램이 적재되는 시간 또는 실행 시간에 링크되기 때문에 정적 링크를 사용할 때보다 성능이 약간 떨어짐. e : 임의의 메모리 절대 주소로 참조할 수 없음. 동적 라이브러리는 다른 프로세스를 통해 적재되고 나면 서로 다른 주소 공간을 가지게 되는데, 절대 주소를 사용하면 다른 프로세스에서 해당 주소가 유효하지 않을 수 있습니다.
 

2장

  1. 다음은 CPU가 실행하는 명령어가 어디서 오는지 설명한 그림이다(수동 실행). 빈칸을 채우시오.
notion image
  1. 다음은 프로세스 주소 공간에 대한 그림이다. 왼쪽에서 오른쪽으로 변화한 의의와 오른쪽 그림에서 주의할 점를 서술하시오.
notion image
  1. 스레드 풀의 주요 특징으로 올바른 것을 모두 고르시오.
    1. A. 작업이 끝날 때마다 스레드를 종료하고 새로 생성한다.
      B. 미리 정해진 수의 스레드를 생성하여 재사용한다.
      C. 스레드 풀 내 스레드 수를 일정하게 관리한다.
      D. 스레드 풀 내 스레드에 작업을 전달하기 위해 작업 대기열을 사용한다.
  1. 다음 중 스레드 안전인 코드를 모두 고르시오
// 1번 int global_num = 0; int func() { ++global_num; return global_num; } // 2번 int funcA() { mutex l; l.lock(); func(); l.unlock(); } // 3번 int func(int *num) { ++(*num); return *num; } // 4번 void funcA() { int a = 100; int b = func(&a); }
  1. 다음 중 스레드 안전 코드를 구현하는 방법으로 올바르지 않은 것은? 1. 스레드 전용 저장소 2. 읽기전용 3. 스레드 간 데이터 공유 4. 원자성 연산 5. 동기화 시 상호 배제
  1. 블로킹과 동기 그리고 논블로킹과 비동기 간의 차이에는 어떤 게 있나요?
  1. 다음 그림에서 이벤트 순환, 코루틴, 스레드를 블로킹과 논블로킹으로 구분하시오
notion image
7-2. 위 그림의 설계 방법은?
정답
  1. 소스 파일, 컴파일러, 실행파일, 디스크, 메모리
  1. 의의: 실행 흐름이 동일한 프로세스 주소 공간을 공유하므로 프로세스 간 통신을 하지 않아도 된다. 주의할 점: 스레드를 생성하면 프로세스의 메모리 공간이 소모됨.
  1. B, C, D A는 스레드 여러 개를 미리 생성해 두고, 스레드가 처리할 작업이 생기면 해당 스레드에 처리를 요청함.
  1. 2번 : 함수를 호출하기 전에 잠금으로 보호하면 스레드 안전임. 잠금으로 전역 변수를 간접적으로 보호함. 4번 : 전달된 매개변수가 스레드 전용 리소스인 지역 변수이기 때문에 funcA 함수를 호출하는 스레드가 몇 개든 서로 간섭하지 않음.
  1. 3번. 스레드 간에 데이터를 공유하는 것이 스레드 안전성을 저해할 수 있음.
  1. sum과 같은 단순 동기인 함수 호출을 했다고 해서 블로킹되거나 스레드가 일시 중지되지 않음. 논블로킹도 계속 체크를 한다면 전체적인 관점에서 동기일 수 있음.
    1. 구분
      블로킹
      논블로킹
      동기
      호출자가 작업 완료까지 멈춤
      호출자가 상태를 지속적으로 확인 (폴링)
      비동기
      작업 완료까지 기다림 (드물게 사용)
      작업 완료 후 알림 (이벤트 기반)
      • 이벤트 순환과 코루틴: 논블로킹
      • 스레드: 일반적으로 논블로킹 환경에서 사용되지만, 특정 상황에서는 블로킹 작업을 처리할 수 있음.
       
    1. 이벤트 순환(Event Loop):
        • 논블로킹: 이벤트 순환은 epoll을 통해 I/O 작업의 상태를 감시하면서, 작업이 완료될 때까지 기다리지 않고 다른 작업을 처리합니다. 즉, 비동기적으로 여러 I/O 요청을 처리합니다.
    2. 코루틴(Coroutine):
        • 논블로킹: 코루틴은 논블로킹 작업의 중요한 구성 요소로, 실행 중단 및 재개가 가능한 경량 프로세스입니다. I/O 작업 완료 시 이벤트 순환으로부터 실행 제어를 전달받아 비동기적으로 실행됩니다.
    3. 스레드(Thread):
        • 블로킹: 스레드는 CPU에서 실행되는 단위로, 각 코루틴이 작업 스레드에서 실행됩니다. 다만, 코루틴이 논블로킹 I/O 작업에 의존하므로, 스레드 자체는 블로킹 상태로 보이진 않습니다.
        • 그러나 특정 상황에서 동기적 작업을 수행하면 해당 스레드는 블로킹 상태가 될 수 있습니다.
7-2. 반응자 패턴

3장

  1. 객체는 보통 몇 바이트인가?
  1. 포인터에 대해 다음을 설명하시오. a. 개념 b. 목적 c. 포인터를 한번 더 추상화한 것
  1. 프로세스 주소 공간의 영역과 역할을 올바르게 연결하시오.
a. 코드 영역 b. 스택 영역 c. 힙 영역 d. 데이터 영역
1. 동적 메모리 할당 2. 실행 파일 초기화 3. 함수 실행 시 정보 저장
 
  1. 함수 호출 시 x86-64에서는 대부분의 경우 매개변수의 전달과 반환값을 가져오는 작업을 레지스터로 한다. 만약 전달된 매개변수 수가 사용 가능한 레지스터 수보다 많다면 어떻게 해야 할까?
  1. 메모리를 효율적으로 할당하기 위해서 메모리 정보에 어떤 정보가 있어야 할까?
  1. 계층적 관점에서 전체 시스템 모습을 그릴 때 어떤 계층으로 이루어져 있는가? 그리고 malloc과 memory pool이 속한 곳은 어디인가?
  1. segmetation falut 와 page fault 가 무엇인가
  1. 다음 중 malloc과 메모리 풀에 대한 설명으로 올바르지 않은 것은? a. malloc 함수는 요청한 크기만큼의 메모리를 동적으로 할당하고, 할당된 메모리의 시작 주소를 반환한다. b. 메모리 풀은 미리 할당된 고정 크기의 메모리 블록을 관리하여, 메모리 할당과 해제를 빠르게 수행할 수 있도록 돕는다. c. 메모리가 부족하면 malloc에 새로운 메모리 조각을 요청하는데, 이때 새로운 메모리 조각의 크기는 항상 이전 메모리 조각의 두 배여야 한다. d. 메모리 풀은 동적으로 크기가 변하는 메모리 블록을 지원하여, 다양한 크기의 메모리 요청을 처리하기 적합하다. e. malloc은 C 언어에서 메모리를 동적으로 할당하는 표준 라이브러리 함수로, 할당된 메모리는 명시적으로 해제해야 한다.
  1. SSD를 메모리로 쓸 수 없는 이유는 여러 가지인데 그 중 자신이 생각하는 가장 핵심적으로 쓸 수 없는 이유는?
정답
  1. 12 바이트
  1. a : 메모리 주소를 더 높은 수준으로 추상화한 것 b : 간접 주소 지정을 감싸기 위함 c : 참조
  1. a, d - 2 c -1 b - 3
  1. 매개변수 수가 레지스터 수보다 많으면 나머지 매개변수는 스택 프레임에 직접 넣을 수 있기 때문에 새로 호출된 함수가 이전 함수의 스택 프레임에서 매개변수를 가져옴.
  1. 머리 정보, 페이로드, 꼬리정보 (flag, 할당 가능한 메모리 조각을 포함함)
  1. 응용 프로그램 → 표준 라이브러리 → 운영 체제 → 하드웨어 malloc은 표준 라이브러리 계층에 속함. 메모리 풀은 응용 프로그램의 일부임.
  1. 세그멘테이션 폴트는 프로그램이 접근할 수 없는 메모리 영역에 접근하려고 할 때 발생하는 오류입니다. 페이지 폴트는 프로세스가 접근하려는 페이지가 메모리에 존재하지 않을 때 발생하는 이벤트입니다.
  1. d. 메모리 풀은 특정 상황에 맞춰 구현됨. 범용 메모리 할당자는 malloc임. 참고) malloc을 사용하여 동적으로 할당한 메모리는 명시적으로 해제해야 합니다. C 언어에서는 free 함수를 사용하여 할당된 메모리를 해제할 수 있습니다.
  1. 목적에 다르게 만들어짐..? 아키텍처도 그렇고 SSD는 비휘발성 메모리를 저장하는 목적이지 할당하고 해제하는 역할이 아니기 때문.
책 질문
  1. 매개변수가 너무 많아 레지스터에 저장되지 못한다는 정보는 어떻게 알 수 있나
  1. 스택 영역의 증가와 감소는 구체적으로 어떻게 구현되나
  1. 이를 구현하는 책임은 누구에게 있나
  1. 스레드 전용 저장소를 사용할 때, 스레드 A의 실행이 완료된 후에도 다른 스레드에서 해당 메모리를 계속 사용한다면, 해당 메모리는 스레드 A에 속해 있음에도 스레드 B에서 이를 해제야 함. 이를 어떻게 해결할 수 있나?
책 질문 답
레지스터와 스택:
CPU는 데이터를 처리하기 위해 레지스터를 사용합니다. 레지스터는 매우 빠른 접근 속도를 가지지만 수가 제한적입니다. 일반적으로 x86 아키텍처에서는 8개, x86-64 아키텍처에서는 16개 정도의 일반 목적 레지스터가 있습니다. 스택은 메모리의 일부분으로, 함수 호출 시 매개변수, 지역 변수, 반환 주소 등을 저장하는 데 사용됩니다. 스택은 레지스터보다 느리지만, 더 많은 데이터를 저장할 수 있습니다. 호출 규약 (Calling Convention):
호출 규약은 함수 호출 시 매개변수를 어떻게 전달할지를 정의합니다. 예를 들어, x86-64 ABI에서는 첫 6개의 정수형 매개변수를 RDI, RSI, RDX, RCX, R8, R9 레지스터에 저장하고, 나머지 매개변수는 스택에 저장합니다. 만약 함수가 7개 이상의 매개변수를 받는다면, 7번째 매개변수부터는 스택에 저장됩니다. 이 경우, 스택 포인터(SP)가 조정되어 스택에 매개변수가 저장됩니다. 어셈블리 코드 분석:
컴파일된 프로그램의 어셈블리 코드를 보면, 매개변수가 어떻게 전달되는지를 확인할 수 있습니다. 예를 들어, 함수 호출 시 call 명령어가 사용되고, 매개변수는 mov 명령어를 통해 레지스터나 스택에 저장됩니다. 매개변수가 레지스터에 저장되는 경우, 해당 레지스터에 대한 mov 명령어가 보이고, 스택에 저장되는 경우 push 명령어가 사용됩니다. 디버깅 및 성능 분석:
디버거를 사용하여 프로그램을 실행하고, 함수 호출 시 레지스터와 스택의 상태를 확인할 수 있습니다. 예를 들어, GDB와 같은 디버거를 사용하여 레지스터의 값을 확인하고, 스택의 내용을 검사하여 매개변수가 어떻게 전달되는지를 분석할 수 있습니다. 성능 분석 도구를 사용하면 함수 호출 시 매개변수 전달 방식에 대한 정보를 수집할 수 있으며, 이로 인해 성능 병목 현상을 식별할 수 있습니다. 이러한 저수준 관점에서의 분석을 통해 매개변수가 너무 많아 레지스터에 저장되지 못하는 상황을 이해하고 확인할 수 있습니다. 2. 스택 영역의 증가와 감소는 스택 포인터를 통해 관리되며, push와 pop 명령어를 통해 구현됩니다. 3.
  1. 운영 체제 메모리 관리: 운영 체제는 프로세스의 메모리 공간을 관리하며, 스택 영역을 포함한 각종 메모리 영역(힙, 데이터 세그먼트 등)의 크기와 위치를 결정합니다. 운영 체제는 프로세스가 실행될 때 스택을 위한 메모리 공간을 할당하고, 스택이 오버플로우하지 않도록 감시합니다. 스택 포인터 관리: 운영 체제는 스택 포인터의 초기값을 설정하고, 함수 호출 및 반환 시 스택 포인터의 값을 적절히 조정합니다. 또한, 예외 상황(예: 스택 오버플로우 발생 시)에 대한 처리를 담당합니다.
  1. 컴파일러 코드 생성: 컴파일러는 고급 프로그래밍 언어로 작성된 코드를 기계어로 변환할 때, 함수 호출 및 반환, 지역 변수의 할당 등을 처리합니다. 이 과정에서 스택에 데이터를 푸시하거나 팝하는 명령어를 생성합니다. 스택 프레임 관리: 각 함수 호출 시 컴파일러는 스택 프레임을 생성하여 매개변수, 반환 주소, 지역 변수를 저장합니다. 이 스택 프레임의 크기와 구조는 컴파일러의 구현에 따라 달라질 수 있습니다.
  1. 프로그래머 코드 작성: 프로그래머는 함수 호출 및 지역 변수를 정의하는 코드를 작성합니다. 이 코드가 컴파일러에 의해 스택 조작 명령어로 변환되므로, 프로그래머는 스택 사용에 대한 이해가 필요합니다. 잘못된 스택 사용(예: 너무 깊은 재귀 호출, 스택 크기 초과 등)은 프로그램의 안정성에 영향을 미칠 수 있습니다. 결론 결국, 스택 영역의 증가와 감소를 구현하는 책임은 운영 체제와 컴파일러에 있으며, 프로그래머는 이 두 요소가 올바르게 작동하도록 코드를 작성하는 역할을 합니다. 이 세 가지 요소가 협력하여 스택 메모리를 효율적으로 관리하고, 프로그램의 실행을 지원합니다.
4.
참조 카운팅(Reference Counting):
메모리를 할당할 때, 각 스레드가 해당 메모리를 사용할 때마다 참조 카운트를 증가시키고, 사용이 끝나면 참조 카운트를 감소시킵니다. 참조 카운트가 0이 되면 메모리를 해제합니다. 이를 통해 여러 스레드가 메모리를 공유할 수 있으며, 마지막으로 사용한 스레드가 메모리를 해제하게 됩니다. 스레드 안전한 메모리 관리:
메모리 해제를 위한 동기화 메커니즘을 사용하여, 스레드 A가 종료된 후에도 스레드 B가 해당 메모리를 안전하게 사용할 수 있도록 합니다. 예를 들어, 뮤텍스(mutex)나 세마포어(semaphore)를 사용하여 메모리 접근을 제어하고, 메모리 해제를 스레드 B가 완료할 수 있도록 합니다. 스레드 풀(Thread Pool):
스레드 풀을 사용하여 스레드 A가 작업을 완료한 후에도 해당 메모리를 스레드 풀에서 관리하도록 할 수 있습니다. 스레드 풀은 작업이 완료된 후에도 메모리를 유지하고, 다른 스레드가 필요할 때 재사용할 수 있도록 합니다. 메모리 관리 객체 사용:
메모리 관리 객체를 만들어, 각 스레드가 메모리를 요청하고 해제할 수 있도록 합니다. 이 객체는 메모리의 소유권을 관리하고, 스레드 A가 종료된 후에도 스레드 B가 메모리를 사용할 수 있도록 합니다. 스레드 간 데이터 공유:
스레드 A가 사용하는 데이터를 스레드 간에 공유할 수 있도록 설계합니다. 예를 들어, 전역 변수나 공유 메모리 영역을 사용하여 스레드 B가 스레드 A의 데이터를 사용할 수 있도록 합니다. 이 경우, 데이터의 동기화와 일관성을 유지하는 것이 중요합니다.
 

4장

  1. halt 명령어에 대한 틀린 설명을 고르시오.
    1. CPU 내부의 일부 모듈을 절전상태로 전환하여 전력 소비를 줄임
    2. 가급적 CPU를 절전 상태로 유지하기 위해 사용됨
    3. 커널상태에서 CPU로만 실행할 수 있음
    4. sleep 같은 함수가 해당됨
    5. 컴퓨터 입장에서 CPU가 가장 많이 실행하는 명령어임
  1. 2의 보수 표현은 덧셈 연산에서 어떤 장점을 제공하나요?
  1. 명령어 실행이 완료되지 않은 시점에 CPU는 어떤 분기의 명령어를 파이프라인에 넣어야 할지 어떻게 알 수 있나요?
  1. CPU 코어수와 스레드 수 사이 어떤 관계가 있을까요?
  1. 다음 중 RISC 설계 철학에 해당하지 않는 것은?
    1. Load/Store 아키텍처를 채택한다.
    2. 모든 명령어는 동일한 실행 시간을 가진다.
    3. 복잡한 작업을 단일 명령어로 처리한다.
    4. 많은 레지스터를 사용한다.
  1. CISC 설계에서는 어떤 이유로 명령어가 복잡한 경우가 많은가요?
    1. 코드를 간결하게 하기 위해
    2. 실행 속도를 높이기 위해
    3. 메모리 사용을 줄이기 위해
    4. 레지스터를 효율적으로 사용하기 위해
  1. 물리 CPU 코어가 운영 체제에 환격을 심어 실제로 컴퓨터는 시스템에 물리 CPU 코어가 하나만 있지만 운영 체제는 논리적으로 CPU 코어가 여러 개 있는 것으로 인식하게 하는 기술을 뭐라고 하나요?
  1. 다음 중 현재 실행 중인 명령어의 주소를 저장하는 레지스터는 무엇인가요?
    1. 스택 포인터 (Stack Pointer, SP)
    2. 명령어 레지스터 (Instruction Register, IR)
    3. 프로그램 카운터 (Program Counter, PC)
    4. 상태 레지스터 (Flag Register)
정답
  1. d. 프로세스 일시 중지는 halt 명령어와 다름. sleep은 한 프로세스만 일시중지함. 여전히 다른 프로세스가 실행 상태라면 CPU는 유휴 상태로 진입할 수 없음.
  1. 2의 보수 표현은 덧셈 연산만으로 뺄셈을 처리할 수 있다는 장점이 있습니다. 예를 들어, A - B 연산을 수행할 때, B의 2의 보수를 구한 뒤 A + (B의 2의 보수)로 계산하면 뺄셈이 가능합니다. 이는 하드웨어 구현을 간소화하고, 덧셈기만으로 뺄셈 연산까지 수행할 수 있게 해줍니다.
  1. CPU는 어디로 분기할 가능성이 있는지 추측을 합니다. 추측이 맞았다면 파이프라인은 계속 앞으로 흘러갈 것이고 틀렸다면 이미 실행 중이던 잘못된 분기 명령어를 전부 무효화합니다. 이때 CPU 추측이 틀리면 성능 손실이 발생합니다. 고급 프로그래밍 언어를 사용하더라도, 구현 원리를 이해한다면 CPU를 더 잘 활용하는 코드를 작성할 수 있다!
  1. CPU 코어수와 스레드 수 사이 어떤 필연 관계도 없음. CPU는 하드웨어인데 반해 스레드는 소프트웨어 개념이고 실행 흐름이자 작업임. 단일 코어 시스템에서도 얼마든지 많은 스레드를 생성할 수 있다. (메모리가 충분하고 운영 체제에 제한이 없어야 함) CPU는 근본적으로 자신이 실행하는 명령어가 어떤 스레드에 속하는지 이해하지 못함. 이를 이해해야 하는 것은 운영체제임.
  1. C. RISC는 복잡한 작업을 단일 명령어로 처리하지 않고, 단순한 명령어를 조합하여 작업을 처리하는 철학을 따릅니다.
  1. A. CISC는 복잡한 명령어를 사용해 동일한 작업을 적은 명령어로 표현하며, 프로그래머가 더 간결하게 코드를 작성할 수 있도록 설계되었습니다.
  1. 하이퍼스레딩 (하드웨어 스레드)
  1. 3) 프로그램 카운터 (Program Counter, PC), 프로그램 카운터(PC)는 CPU가 다음에 실행해야 할 명령어의 메모리 주소를 저장합니다. 명령어 실행이 완료되면 PC의 값이 증가하거나 점프(Jump) 명령어에 따라 변경됩니다.
 

5장

  1. 다음은 최신 컴퓨터 시스템의 저장 체계를 구성하는 요소이다. 저장 용량이 작은 순서대로 나열하세요
    1. 분산 파일 시스템
    2. L1 캐시
    3. L2 캐시
    4. L3 캐시
    5. 레지스터
    6. 디스크
    7. 메모리
  1. 전체 저장 체계가 최대 성능을 발휘하려면 프로그램이 매우 캐시 친화적이어야 한다. 어떻게 캐시 친화적인 프로그램을 작성할까?
  1. 다중 스레드 성능 방해자로 어떤 게 있나요?
  1. 캐시와 비순차적 실행의 관계?
정답
  1. 레지스터 > L1 캐시 > L2 캐시 > L3 캐시 > 메모리 > 디스크 > 분산 파일 시스템
  1. 공간적, 시간적 지역성 활용 struct 구조체 재배치 : 연결 리스트(Linked List)는 동적 메모리 할당을 사용하기 때문에 연속적인 메모리 배치가 어려워 캐시 친화적이지 않다는 단점이 있습니다. 하지만 공간적 지역성을 이용해 next 포인터와 value 값을 함께 배치하면 최적화할 수 있음 핫 데이터와 콜드 데이터 분리 : 배열 arr를 다른 구조체에 넣고 List 구조체 안에 이 구조체를 가리키는 포인터를 추가함 행 우선 접근 *최적화 시 분석 도구를 사용해 캐시의 적중률이 시스템 성능의 병목이 되는지 판단해야 함. 병목이 되지 않는다면 굳이임.
  1. 캐시 튕김 : 캐시 무효화를 일으킴 가짜 공유 : 여러 스레드가 같은 캐시 라인(64B) 내의 다른 변수를 수정하면 캐시 일관성을 유지하기 위해 불필요한 캐시 미스와 메모리 동기화가 발생
  1. 비순차적 실행이 효과적으로 작동하려면 다음에 실행할 수 있는 명령어가 충분히 많아야 함.
    1. 그러나 캐시 미스로 인해 메모리 접근이 오래 걸리면, CPU가 실행할 수 있는 명령어가 줄어들어 성능이 급격히 저하될 수 있음.
      💡 즉, 캐시 미스가 많아지면 비순차적 실행의 이점을 살리기 어려워짐.
 

6장

  1. 키보드를 쳤을 때 화면이 친 글자가 나오는 과정을 설명해주세요
  1. CPU는 LOAD, STORE 명령어 등 메모리를 읽고 쓰는 특정 명렁어가 있습니다. 이 명령어를 실행하면 CPU는 메모리를 읽는지 아님 장치 레지스터를 읽는지 어떻게 아나요?
  1. 사용자가 언제 키보드를 누를지 확실치 않은데 언제 데이터를 어떻게 읽어야 하나요?
  1. 인터럽트 처리와 함수 호출의 차이는 무엇일까요?
  1. 중단된 프로그램의 실행 상태를 저장하고 복원하는 방법은 무엇일까요?
  1. 프로그램이 파일을 읽는 과정을 설명하세요
정답
  1. CPU는 장치 레지스터를 읽고 쓰는 특정한 기계 명령어를 설계할 수 있음. 이 특정한 기계 명령어를 입출력 명령어라고 하는데, x86의 IN과 OUT 기계 명령어가 이에 해당함. 그래서 사용자가 키보드의 키를 누르면 그 정보는 장치 레지스터에 저장되고 CPU가 이를 읽는 것임. 이때 어떤 장치 레지스터를 읽고 써야 하는지는 장치마다 고유한 주소가 부여되고 입출력 명령어에 장치 주소를 지정해서 CPU가 입출력 명령어를 실행하면 하드웨어 회로가 어떤 장치 레지스터를 읽고 써야 하는지 알 수 있음.
  1. 기계 명령어 관점에서 CPU에 보이는 것은 주소 공간이며, CPU는 주소 공간의 특정 주소에서 데이터를 읽어 온다는 사실만 알고 있음. 즉, CPU는 해당 주소의 데이터가 어디에서 오는지 관심을 가질 필요가 없음. 그렇기 때문에 주소 공간의 일부분을 장치에 할당할 수 있음 (memory mapping input and output.
  1. 폴링 : 계속 검사하기, 항상 불필요한 순환, 대기가 일어남 인터럽트 구동식 입출력 : CPU는 실행 중인 현재 작업의 우선순위가 인터럽트 요청보다 높은지 판단함. 인터럽트가 더 높다면 현재 작업 실행을 일시 중지하고 인터럽트를 처리. 인터럽트 처리 후 다시 현재 작업으로 돌아옴. 단 이 방식은 원래 실행되던 작업의 실행 상태를 저장하고 복원하는데 시간을 낭비함.
  1. 사용자 상태의 함수 호출만 고려했을 때 점프와 반환을 포함하고 있다는 점에서 유사함. 함수 호출은 단일 스레드 내부에서만 발생하고, 동일한 실행 흐름 내에 존재함. 반면에 인터럽트 처리 점프는 서로 다른 두 실행 흐름을 포함하므로 함수 호출에 비해 인터럽트 점프는 저장해야 할 정보가 훨씬 많음.
  1. 커널에 위치한 스택으로(first in last out).
  1. CPU가 read 계열의 함수 호출. 해당 함수는 저수준 계층에서 시스템 호출을 이용하여 운영 체제에 파일 읽기 요청을 보냄. 이 요청은 커널에서 디스크가 이해할 수 있는 명령어로 변환되어 디스크로 전송됨. 운영 체제는 외부 장치의 입출력 작업이 느리기 때문에 현재 프로세스의 실행을 일시 중지하고 입출력 블로킹 대기열에 넣음. 디스크는 운영체제의 입출력 요청에 따라 DMA 작동 방식을 사용하여 데이터를 특정 메모리 영역으로 복사하는 작업을 시작함. 그 동안 CPU는 준비 완료 대기열에 존재하는 프로세스를 실행함. 디스크가 메모리에 복사하는 작업이 완료되면, 디스크는 CPU에 인터럽트 신호를 보냄. CPU는 인터럽트 신호를 받은 후 처리가 중단되었던 함수로 점프하며, 이때 운영 체제는 실행하던 프로세스를 입출력 블로킹 대기열에 꺼내 다시 준비 완료 대기열에 넣음. 그리고 프로세스 마저 처리. 파일을 열 때 커널은 파일 서술자를 반환하며, 파일 작업을 실행할 때 해당 파일 서술자를 커널에 전달해 주어야 함. 커널은 이 숫자를 얻은 후 해당 숫자에 대응하는 파일에 관련된 모든 정볼르 찾아 파일 작업을 완료할 수 있음.
책갈피
  1. 일관성 문제로 상응하는 캐시의 데이터를 즉시 메모리에 갱신하여 일관성 문제가 나타나지 않도록 하면 캐시가 왜 필요하지?