[스터디] 직접 메모리 접근

Jun_k·2026년 4월 18일

CS

목록 보기
5/19

왜 DMA가 필요한가?

컴퓨터의 모든 작업은 원래 CPU를 거쳐야 한다.
하지만 주변 장치(디스크, 네트워크 카드 등)에서 메모리로
대량의 데이터를 옮길 때마다 CPU가 하나하나 관여한다면,
정작 중요한 연산을 처리할 시간이 부족해진다.

이를 해결하기 위해 "데이터 전송만 전문적으로 담당하는 대리인"을 세웠는데
이것이 바로 DMA 제어기이다.


DMA의 3가지 레지스터

  • DMA 제어기 내부에는 각 주변 장치를 관리하기 위한 3가지 핵심 정보가 들어있다.
    이 값들은 운영체제(OS)가 설정한다.

  • 주소 레지스터: 데이터가 저장될 메모리의 위치 주소, "어디에 놓을까?"
    (목적지 주소)

  • 계수 레지스터: 전송해야 할 데이터의 남은 크기, "얼마나 남았나"
    (잔여 수량, Count)

  • 제어 레지스터: 읽기(0)인지 쓰기(1)인지 결정, "가져올까, 보낼까"
    (작업의 종류)


시스템 버스 사용권

데이터는 시스템 버스라는 도로를 통해 이동한다.
하지만 도로는 하나인데 CPU와 DMA가 동시에
데이터를 보내려 하면 충돌이 발생한다.

쉽게 말하면 CPU와 DMA 제어기는 서로 독립적인 장치이고,
누가 도로를 쓸지 결정하는 중재의 과정이 명확하지 않으면
당연히 데이터 충돌이 일어나서 데이터가 오염될 수 있다.
이를 방지하기 위한 4단계 과정을 아래와 같이 정리해 보았다.

  • DMA 요청: 주변 장치가 DMA 제어기에게
    "나 데이터 좀 보낼게, 도로 좀 빌려줘"라고 요청한다.

  • 버스 요청: DMA 제어기가 CPU에게
    "비서인 제가 도로를 좀 써야겠습니다. 권한을 넘겨주세요"라고 신호를 보낸다.

  • 버스 승인: CPU가 "알겠다. 지금은 내가 도로를 안 쓰니 네가 써라"라며
    사용권을 넘겨준다.

  • DMA 승인: DMA 제어기가 주변 장치에게
    "자 권한 따왔어. 이제 데이터 보내보자."라고 최종 승인을 내린다.


무중단 CPU

  • 직접 메모리 접근을 한다고 해서 CPU가 하던 일을 멈추는 것이 아니다.

  • CPU가 일하는 시간은 크게 두 부분으로 나뉜다.

  • 버스 사용 구간: 명령어 인출(Fetch), 데이터 인출/저장
    (도로 위를 달리는 시간)

  • 내부 연산 구간: 명령어 해석(Decode), 실행(Execute)
    (사무실 안에서 머리 쓰는 시간)

  • DMA는 CPU가 '사무실에서 머리를 쓰는 시간(내부 연산)'에 몰래 도로를 사용한다.
    CPU 입장에서는 자기가 도로를 안 쓸 때만 DMA가 지나가므로
    작업이 중단되지 않는 것처럼 느껴진다.
    이를 사이클 스틸링이라 부른다.


전체 동작 과정: 쓰기(Write)와 읽기(Read)

  • 컴퓨터의 관점에서 봤을 때 쓰기는 주변 장치 데이터를 메모리에 넣는 것이고,
    읽기는 메모리에 있는 데이터를 주변 장치로 꺼내는 것이다.

  • 직접 메모리 접근 쓰기 (예: 파일 불러오기)

    • 스토리지에 있는 "DOG"라는 데이터를 메모리로 옮겨서 프로그램이 읽게 함.

    • 1단계 (설정): OS가 CPU를 대기시키고,
      DMA 레지스터에 "메모리 주소 X, 크기 3, 작업: 쓰기"를 입력한다.
      스토리지에도 "파일 읽어와"라고 명령한다.

    • 2단계 (전송): 스토리지가 버스 권한을 얻으면,
      DMA가 주소를 찍어주고 데이터를 쏜다.
      한 글자 보낼 때마다 주소는 +1,
      계수는 -1을 하며 계수가 0이 될 때까지 반복한다.

    • 3단계 (종료): 전송이 끝나면 DMA가 CPU에 "다 끝났습니다."라고
      인터럽트를 보내고, CPU는 잠자던 프로세스를 깨워
      "DOG" 데이터를 쓰게 한다.

  • 직접 메모리 접근 읽기 (예: 파일 저장하기)

    • 메모리에 있는 "CAT" 데이터를 스토리지에 저장함.

    • 1단계 (설정): OS가 DMA에
      "메모리 주소 Y에 있는 'CAT'을 가져가라"고 설정한다.
      스토리지에도 "데이터 들어올 테니 저장 준비해"라고 명령한다.

    • 2단계 (전송): DMA가 메모리에
      "Y 주소에 있는 데이터 도로로 내보내"라고 신호를 주면,
      메모리가 데이터를 내놓고 스토리지가 이를 받아 저장한다.
      역시 주소 증가, 계수 감소를 반복한다.

    • 3단계 (종료): 저장이 완료되면 인터럽트를 통해
      CPU에 알리고 작업을 마무리한다.


DMA 활용 예시 - 카프카 (제로 카피)

  • 카프카가 대용량 데이터를 아주 빠르게 처리할 수 있는 핵심 비결 중
    하나가 바로 DMA를 이용한 '제로 카피(Zero-Copy)' 기술이다.

  • 필요 개념 설명

    • 커널 메모리: 컴퓨터 메모리는 유저 영역과 커널 영역으로 나뉜다.
      유저 영역은 내가 만든 자바 프로그램이나 애플리케이션이 실행되는 일반적인 공간이며 보안상 디스크나 네트워크 같은 하드웨어에 직접 접근 권한이 없다.
      커널 영역은 커널이 사용하는 영역이며 당연히 하드웨어를 직접 제어할 수 있는 권한을 가지고 있다.

    • 네트워크 카드: 일반적인 랜 카드를 의미하고, 컴퓨터 내부의
      0과 1같은 디지털 데이터를 실제 전기 신호로 바꾸어 케이블로 쏴주는 관문.

    • 소켓 버퍼: 데이터를 네트워크로 보낼 때, 한 글자씩 실시간으로
      보낼 수는 없기에 모아 놨다가 한꺼번에 보내는 공간이다.
      (커널 메모리에 존재한다.)

  • 일반적인 방식 (비효율 방식)

    • 디스크 → 커널 메모리 → 유저 메모리(Java) → 소켓 버퍼 → 네트워크 카드

    • 중간에 CPU가 데이터를 유저 영역으로 복사하고,
      다시 소켓으로 복사하는 '노가다'를 두 번이나 함.

    • 데이터 전송하느라 정작 로직 처리는 느려진다.

  • 제로 카피 방식 (Kafka)

    • 디스크 → 커널 메모리 → 네트워크 카드 (중간 단계 생략)

    • 카프카가 OS에 "복사하지 말고 바로 쏴"라고 명령(sendfile)한다.

    • DMA가 커널 메모리에서 네트워크 카드로 데이터를 직접 쏴버린다.
      CPU는 복사 업무에서 완전히 해방된다.

  • 부연 설명

    • 카프카는 데이터를 수정하지 않고 그대로 전달만 하는 경우가 많다.

    • 그래서 굳이 CPU를 써서 유저 메모리(Java)로 데이터를 가져올 필요가 없다.

    • DMA에게 명령을 내려 커널 메모리에서 네트워크 카드로 바로 직행시킨다.

    • 결과적으로 CPU 점유율은 낮아지고,
      전송 속도는 하드웨어 한계치까지 올라간다.


요약

  • DMA 제어기는 단순히 "전송 장치"가 아니라,
    CPU의 효율성을 극대화하기 위해 탄생한 중재자이다.

  • CPU의 I/O 부하를 줄여 시스템 전체 성능을 높이기 위해 사용한다.

  • CPU가 버스를 안 쓰는 틈새 시간(내부 연산)을 이용하기 때문에
    멈추지 않는다.

  • 결과적으로 대량의 데이터 전송 중에도 백엔드 서버의 CPU는
    다른 복잡한 로직을 끊임없이 처리할 수 있게 된다.

profile
개발을 즐겨보자.

0개의 댓글