책너두 (컴퓨터 밑바닥의 비밀) 17일차 메모리 할당할 때 저수준 계층에서 일어나는 일

  • CPU 실행상태
  • x86 CPU는 네 가지 특권 단계를 제공함.
    • CPU의 여러 가지 동작 상태를 나타냄.
    • 숫자가 작을 수록 CPU의 특권은 커짐.
      • 여기서 특권은, 일부 명령어를 실행할 수 있는지를 나타냄.
  • 일반적으로 시스템은 CPU 특권 단계 0, 3 두 단계만 이용함.
    • 3단계는 사용자 상태(user mode), 0단계는 커널 상태(kernel mode) 라고 함.
  • 커널 상태와 사용자 상태
  • CPU가 운영 체제의 코드를 실행할 때 바로 커널 상태에 놓임.
    • 커널 상태에서는 CPU가 모든 기계 명령어를 실행할 수 있고, 모든 주소 공간에 접근할 수 있음.
    • 제한 없이 하드웨어에 접근할 수 있음.
  • 프로그래머가 작성한 일반적인 코드를 CPU가 실행할 때는 사용자 상태에 해당함.
    • 특정 주소 공간에 절대 접근할 수 없음.
    • 이것이 바로 유명한 세그먼테이션 오류임.
  • 포털: 시스템 호출
  • 운영 체제는 일반적인 프로그래머를 위해 특정 ‘비밀 코드’를 남겨 둠.
    • 이 비밀 코드를 통해 프로그래머가 운영체제에 서비스를 요청할 수 있음. → 시스템 호출(system call)
    • 시스템 호출을 이용하여 운영 체제가 파일의 읽기, 쓰기, 네트워크 데이터 통신 같은 작업을 응용 프로그램 대신 처리해 줌.
  • 표준 라이브러리: 시스템의 차이를 감춤
  • 시스템 호출은 모두 운영체제와 매우 밀접한 관련이 있음.
    • 리눅스의 시스템 호출은 윈도우 시스템 호출과 완전히 다름.
  • 프로그래머가 시스템 호출을 직접 호출을 사용하면 리눅스 프로그램을 윈도에서 직접 실행할 수 없음.
    • 따라서, 사용자에게서 저수준 계층 간 차이를 감추는 일종의 표준이 필요함.
    • 그러면 프로그래머가 작성한 프로그램을 추가적인 수정 없이 서로 다른 운영 체제에서 실행할 수 있게 됨.
    • C 언어에서 이 일을 하는 것이 바로 표준 라이브러리 임.
    • 표준 라이브러리 코드는 사용자 상태에서도 실행 됨.
  • 일반적으로 프로그래머는 표준 라이브러리를 호출하여 파일을 읽고 쓰며, 네트워크 통신을 수행함.
    • → 표준 라이브러리는 실행 중인 운영 체제에 따라 대응되는 시스템 호출을 선택함.
    • 이로 인해, C 언어에서 동일한 open 함수를 사용하여 리눅스뿐만 아니라 윈도에서 파일을 열 수 있음.
  • 힙 영역의 메모리가 부족할 때
  • 힙 영역과 스택 영역 사이에 여유 공간이 있음.
    • 스택 영역이 함수 호출 단계가 깊어질수록 아래쪽으로 메모리 점유 공간이 늘어남.
    • 힙 영역의 메모리가 부족하면 위쪽으로 더 많이 메모리를 점유하게 됨.
      • malloc (메모리 할당자)는 메모리가 부족해지면 운영 체제에 메모리를 요청해야 함.
      • 리눅스의 모든 프로세스에는 brk 변수가 있음.
      • brk 변수는 브레이크를 의미하며, 힙 영역의 최상단을 가리킴.
      • brk 변수 값을 위로 이동해서 힙 영역을 확장하려면 시스템 호출이 필요함.
  • 운영 체제에 메모리 요청하기: brk
  • 리눅스에서 brk 전용 시스템 호출을 제공함.
    • mmap 등 시스템 호출도 같은 목적으로 사용할 수 있음.
    • mmap이 좀 더 구조가 유연함.
  • 즉, 메모리 할당이 더이상 사용자 상태의 힙 영역에만 국한되지 않기에 메모리 할당 단계가 다음과 같이 달라질 수 있음.
    • 프로그램은 malloc 을 호출하여 메모리 할당을 요청함.
      • malloc 은 표준 라이브러리에 구현되어 있음.
    • malloc 은 여유 메모리 조각을 검색하고, 적절한 크기의 조각을 찾으면 할당함.
      • 이 단계까지는 사용자 상태임.
    • malloc 이 여유 메모리 조각을 찾지 못하면 brk 시스템 호출을 통해 운영 체제에 힙 영역을 늘려 주라고 요청함.
      • brk 는 운영 체제의 일부분이므로 커널 상태임.
      • 힙 영역이 늘어나면 malloc이 다시 한 번 적절한 여유 메모리 조각을 찾아서 할당할 수 있음.
  • 가상 메모리가 최종 보스다
  • 가상 메모리를 지원하는 시스템에서는 위 malloc 메모리 요청 및 운영 체제 힙 영역 확장, 메모리 할당 과정이 전혀 일어나지 않음.
    • 이 과정에서 힙 영역을 포함한 전체 프로세스 주소 공간은 모두 실제 물리 메모리가 아님.
  • 프로세스 입장에서 사용하는 메모리는 모두 가상임.
    • 운영 체제가 프로세스에 보여주는 환상임.
  • malloc 의 호출이 반환되면 프로그래머가 받아 오는 메모리는 가상 메모리임.
    • 실제 물리 메모리가 전혀 할당되지 않은 상태일 수 있음.
  • 실제로 할당한 메모리가 사용되는 순간에 물리 메모리가 할당 됨.
    • 이때, 가상 메모리가 아직 실제 물리 메모리와 연결되어 있지 않으면 내부적으로 페이지 누락 오류가 발생할 수 있음.
    • 운영 체제가 이 오류를 감지하면 페이지 테이블을 수정하여 가상 메모리와 실제 물리 메모리 사상 관계를 설정함.
      • 이걸로 실제 물리 메모리가 할당 됨.
  • malloc 과정은 모두 사용자 상태에 처리 됨.
    • 이어서 프로그램이 할당된 가상 메모리를 사용할 때, 반드시 실제 물리 메모리와 사상 관계가 있어야 함.
    • 이 시점이 되어야만 커널 상태에서 실제 물리 메모리가 할당 됨.
    • 운영 체제만 실제 물리 메모리를 할당할 수 있음.
  • 메모리 할당의 전체 이야기
  • malloc 을 호출하여 메모리를 요청하면 다음 일이 일어남.
  1. malloc 이 여유 메모리 조각을 검색하기 시작함. 적절한 크기 조각을 찾으면 할당함.
  2. malloc이 적절한 여유 메모리를 찾지 못하면 brk 같은 시스템 호출을 통해 힙 영역을 확장하여 더 많은 여유 메모리를 얻음.
  3. malloc이 brk 를 호출하면 커널 상태로 전환 됨.
    • 운영 체제의 가상 메모리 시스템이 힙 영역을 확장하는 작업을 시작함.
    • 이렇게 확장된 메모리 영역은 가상 메모리에 불과하며, 운영 체제는 아직 실제 물리 메모리를 할당하지 않았을 수 있음.
  4. brk 실행이 종료되면 malloc으로 제어권이 돌아가며 CPU도 커널 상태에서 사용자 상태로 전환 됨.
    • malloc은 이제 적절한 여유 메모리 조각을 찾아 반환함.
  5. 프로그램은 메모리를 성공적으로 요청하게됨.
  6. 코드가 새로 요청된 메모리를 읽거나 쓰면, 시스템 내에 페이지 누락 인터럽트가 발생함.
    • 이때 CPU는 다시 사용자 상태에서 커널 상태로 전환됨.
    • 운영 체제가 실제 물리 메모리를 할당하기 시작함.
    • 페이지 테이블 내 가상 메모리와 실제 물리 메모리의 사상 관계가 설정된 후, CPU는 다시 커널 상태에서 사용자 상태로 돌아가 다음을 처리함.

댓글

Designed by JB FACTORY