Java IO

Inyestar·2022년 12월 27일
0

java

목록 보기
1/1
post-thumbnail

소켓 혹은 파일을 다룰 때 습관적으로 선언하던 Buffered 접두사를 이해하기 위해 (여전히 잘 모르지만) 해당 블로그를 작성한다.

Buffer

bufferedCompany 회사가 옆 동으로 이전하게 되었다. A동에서 B동 이동하려면 사무실에서 나와 엘리베이터를 탄 후 1층으로 내려가 옆 건물로 이동하여 다시 엘리베이터를 타고 10층으로 올라가야 한다. 자리마다 짐은 개인이 옮겨야 한다. 사원 snail은 사무실의 키보드, 마우스, 서류 등을 한 번에 한 개씩만 옮겼다. 또 다른 사원 clever는 자신의 짐들을 모두 박스 한 상자에 담아 한 번에 자신의 짐을 모두 B동으로 옮겼다.

이 이야기의 박스는 컴퓨터 세상에서의 Buffer를 의미한다. 디스크에 있는 데이터를 프로세스가 참조할 수 있도록 메모리에 올리는 과정은 생각보다 복잡하다. 이 복잡한 과정을 1byte씩 읽고 1byte씩 쓰기를 진행할 때마다 반복하면 매우 효율적이지 못하다. 그래서 똑똑한 사람들이 메모리에 일정 공간을 할당하여 읽기 먼저 진행하고, 다시 그 일정 공간만큼 쓰기를 진행하도록 임시 공간을 제공해주는 방법을 고안해내었고 우리는 그 공간을 Buffer라고 부른다.

종류

Java에서 제공하는 Buffer는 아래와 같이 크게 두 종류로 구분한다.

Non Direct Buffer

  • JVM의 Heap 영역 내에 공간을 만드는 Buffer
  • 파일을 읽을 때 JNI*를 통해 OS 레벨로 접근이 가능한 코드를 호출하기 때문에 오버헤드가 발생

Direct Buffer

  • 시스템 메모리에 직접 공간을 만드는 Buffer
  • 시스템 메모리에 공간을 만들어야 하기 때문에 Non Direct Buffer 보다 초기화가 오래 걸림
  • 한 번만 초기화하고 지속적으로 사용할 수 있는 구조로 만드는 것이 중요

언제 사용될까?

프로세스는 OS에게 Buffer에 있는 데이터를 가져가거나 채워달라고 요청하는 방식으로 IO를 수행한다. 다음은 (아주 간략하게 요약된) 디스크를 읽는 절차이다.

읽기

1) 프로세스는 OS 언어를 이용해 read()를 호출하여 프로세스의 Buffer가 채워지도록 요청한다.
2) read()가 호출되면 커널은 disk controller에게 하드웨어의 데이터를 가져오라고 명령한다.
3) 명령을 받는 disk controller는 DMA를 통해 커널의 메모리 영역(커널의 Buffer)에 데이터를 쓰기 시작한다.

DMS란 Direct Memory Access의 약자로 하드웨어가 메모리에 직접 접근하여 read/write를 가능하게 하는 기능으로 CPU의 개입 없이 데이터를 전송한다. 물리적인 메모리 주소에만 접근이 가능하다.

4) disk controller가 커널 Buffer에 데이터를 다 채우면 커널은 해당 데이터를 프로세스 영역의 Buffer에 복사한다. 커널은 데이터를 캐싱*하거나 미리 가져오려고 하기 때문에 프로세스가 요청한 데이터는 이미 커널 영역에 존재하고 있을 수도 있다.

disk controller는 커널 Buffer에 데이터를 보내고, 커널은 다시 프로세스 Buffer에 데이터를 보낸다. 두 번이나 copy/paste가 일어나고 있는 것이다!

왜 disk controller는 프로세스의 Buffer에 직접 데이터를 보내지 않을까? 기술적인 이슈가 있었겠지만 이 이슈를 해결하기 위해 가상 메모리가 등장한다.

가상메모리

  • 물리적인 메모리 주소를 대신하여 사용할 수 있는 가상의 주소를 의미
  • 여러 개의 가상 주소는 같은 물리적 메모리 주소를 참조 할 수 있다. 따라서 사용자 영역의 가상 주소와 커널 영역의 가상 주소를 같은 물리적 주소에 매핑이 가능하다.
  • DMA가 커널 영역의 Buffer에 데이터를 전송하면, 똑같은 물리 주소를 참조하고 있는 사용자 영역의 가상 메모리에서도 해당 데이터를 동시에 조회할 수 있다.
  • 같은 물리 주소를 공유하기 위해서는 아래 조건이 충족되어야 한다.
    • 커널과 사용자 Buffer는 같은 page alignment를 공유해야 한다.
    • Buffer는 disk controller가 사용하는 block 크기 단위로 할당 되어야 한다. (512kb)

      OS는 메모리 주소 영역을 page라는 단위로 관리한다. Page는 고정된 크기를 구분 짓는 개념으로 대개 disk block size의 배수이거나 2의 제곱 정도의 크기를 갖는다. 가상 메모리와 물리적 메모리의 페이지 크기는 항상 똑같다.

자꾸 disk controller가 등장하는데, 이 친구는 대체 뭐지? disk controller를 이해하기 위해 파일 시스템부터 알아보자.

파일 시스템

  • 디스크에 저장되어 있는 데이터를 추상화한 개념
  • 데이터를 어떻게 해석하고 정렬하는지에 대한 방식을 결정
  • 우리가 쓴 코드는 직접 하드디스크와 상호 작용하는 것이 아닌 파일 시스템과 상호 작용한다.
  • 사용자 프로세스로부터 파일 읽기에 대한 요청이 들어오면, 파일 시스템 구현체가 요청된 데이터의 위치를 판단한다. 그리고 나서 해당 디스크 섹터를 메모리로 가져온다.
  • 파일 시스템도 메모리의 page 개념을 갖고 있다.
    • 요청된 파일이 어느 page에 있는지 파악한다.
    • 필요한 page를 가져오기 위해 커널 영역에 메모리를 확보한다.
    • 커널 영역의 메모리 page와 파일 시스템의 page를 매핑한다.
    • page faults를 각 메모리 페이지에 생성한다.
      (!) page faults란 메모리에 요청 데이터가 없어 디스크에 해당 데이터를 요청하는 것
    • 가상 메모리 시스템이 page faults를 trap한다.
      (!) trap이란 프로세스가 특정 시스템 기능을 사용하고자 운영체제에게 해당 기능을 요청하는 것
    • 가상 메모리 시스템이 pagin을 스케줄링한다.
      (!) pagein란 디스크에서 메모리로 데이터를 옮기는 것
    • pagein이 완료되면 파일 시스템은 요청된 데이터와 정보를 추출하기 위해 raw data를 조각으로 만들어버린다. (block 단위로 조각 내버리는게 아닐까 추측)

내멋대로 단어 사전

  • 커널 : OS를 동작하게 만드는 핵심 프로그램으로 하드웨어 제어 등 시스템 레벨에서의 역할을 수행한다. 영화에서 해커들이 검정색 화면에서 초록색 무언가를 뚜따뚜따 건드리는 그런 느낌..?
  • 프로세스 : 단순히 디스크에 저장된 데이터가 메모리에 올라가서 어떤 역할을 수행하게 되면 우리는 이걸 프로세스라고 부른다. 바탕화면에서 엑셀 아이콘을 클릭하면 엑셀 창이 뜨는데 이 과정에서 데이터 쪼가리가 메모리에 올라가 친숙한 엑셀 스프레드 시트 창을 보여주는 것.
  • 오버헤드 : A 작업만 하려고 했는데 A 작업하려고 보니까 추가적으로 B 작업이 어쩔 수 없이 수행되어야 할 때, 그러니까 예상치 못한 추가적인 리소스 할당이 필요할 때 보통 오버헤드가 발생한다고 말한다.
  • JVM : OS안에 있는 Java의, Java에 의한, Java를 위한 또 다른 작은 OS. 메모리도 갖고 있고 스택도 있고, CPU 작업(instruction)도 할당하고 뭐 별거 다 한다.
  • JNI : Java 코드에서 native라고 붙여져 있는 메소드들이 있는데 그게 JNI를 이용해서 OS 코드를 호출하는 인터페이스들이다. 디스크를 읽거나 하드웨어를 제어하는 건 커널만이 할 수 있기때문에 커널의 언어 호출이 필요할 때 JNI를 이용한다.
  • 캐싱 : 여기선 디스크에서 한 번 read한 데이터를 날리지 않고 메모리에 일정 기간 동안 저장해두는 걸 의미한다.

참조

profile
Back-end engineer

0개의 댓글