Post

하드웨어와 운영체제

3. 하드웨어와 운영체제

3.1 최신 하드웨어 소개

3.2 메모리

클록 속도가 처음에 비해 수백 배 증가 -> 데이터의 움직이 따라오지 못함

3.2.1 메모리 캐시

그래서 CPU 캐시가 고안됨

캐시 아키텍처를 이용해 액세스 시간을 줄이고 코어가 처리할 데이터를 계속 채워 넣음

프로세서 처리율은 현저히 개선됐지만, 메모리에 있는 데이터를 어떻게 캐시로 가져오고 캐시한 데이터를 어떻게 메모리에 다시 써야 할지 결정이 필요함

-> 캐시 일관성 프로토콜로 해결

프로세서의 가장 저수준에서 MESI 프로토콜

  • Modified: 데이터가 수정된 상태
  • Exclusive: 이 캐시에만 존재하고 메인 메모리 내용과 동일한 상태
  • Shared: 둘 이상의 캐시에 데이터가 들어 있고 메모리 내용과 동일한 상태
  • Invalid: 다른 프로세스가 데이터를 수정하여 무효한 상태

캐시 기술 덕분에 데이터를 신속하게 메모리에서 쓰고 읽을 수 있게 됨

이론적으로 가능한 최대 전송률은 다음 인자에 따라 달라짐

  • 메모리 클록 주파수
  • 메모리 버스 폭
  • 인터페이스 개수

자바 성능을 논할 때는 객체 할당률에 대한 애플리케이션 민감도가 가장 중요

3.3 최신 프로세서의 특성

3.3.1 변환 색인 버퍼(Translation Likkaside Buffer, TLB)

가상 메모리 주소를 물리 메모리 주소로 매핑하는 페이지 테이블의 캐시 역할을 수행

덕분에 가상 주소를 참조해 물리 주소에 액세스하는 빈번한 작업 속도가 매우 빨라짐

3.3.2 분기 예측과 추측 실행

분기 예측은 프로세서가 조건 분기하는 기준값을 평가하는 대기하는 현상을 방지

가장 발생 가능성이 큰 브랜치를 미리 결정하는 휴리스틱 형성

추측이 맞으면 성능 good

3.3.3 하드웨어 메모리 모델

순서에 영향이 없다면 코드 실행 순서를 바꿀 수 있음

하지만, 다른 스레드 입장에서는 영향이 생길 수 있음

락과 volatile을 정확히 알고 사용해야 함

3.4 운영체제

OS의 주 임무는 여러 실행 프로세스가 공유하는 리소스 액세스를 관장하는 일

한정된 리소스 가운데서도 메모리와 CPU 시간은 가장 중요한 쌍벽

메모리 관리 유닛(Memory Management Unit, MMU)을 통한 가상 주소 방식과 페이지 테이블은 메모리 액세스 제어의 핵심으로서, 한 프로세스가 소유한 메모리 영역을 다른 프로세스가 함부로 훼손하지 못하게 함

3.4.1 스케줄러

프로세스 스케줄러는 CPU 액세스를 통제

실행 큐(실행 대상이지만 CPU 차례를 기다려야 하는 스레드 혹은 프로세스 대기 장소)를 이용함

스케줄러는 인터럽트에 응답하고 CPU 코어 액세스를 관리

스케줄러는 할당 시간 끝 무렵에 실행 큐로 스레드를 되돌려서 큐의 맨 앞으로가 다시 실행될 때까지 대기시킴

OS는 그 특성상 CPU에서 코드가 실행되지 않는 시간을 유발

그러므로 실제로 관측한 프로세스에서 나온 통계치는 시스템에 있는 다른 프로세스의 동작에도 영향을 받음

3.4.2 시간 문제

OS는 저마다 다르게 작동

3.4.3 컨텍스트 교환

context switch는 OS 스케줄러가 현재 실행 중인 스레드/태스크를 없애고 대기 중인 다른 스레드/태스크로 대체하는 프로세스

실행 명령과 스택 상태를 교체

컨텍스트 교환은 비싼 작업

커널 모드로의 전환이 특히 비쌈(명령어와 다른 캐시를 어쩔 수 없이 강제로 비워야 함)

리눅스는 이를 최대한 만회하려고 가상 동적 공유 객체(virtual Dynamically Shared Object, vDSO) 사용

부수 효과(side effect)를 일으키지 않으므로 실제로 프리빌리지드 액세스는 필요 없다 -> 성능 향상 가능

3.5 단순 시스템 모델

3.6 기본 감지 전략

애플리케이션이 잘 돌아간다는 건 CPU 사용량, 메모리, 네트워크, I/O 대역푝 등 시스템 리소스를 효율적으로 잘 이용하고 있다는 뜻

성능 진단의 첫 단추는 어느 리소스가 한계에 다다랐는지 밝히는 일

3.6.1 CPU 사용률

CPU 사이클은 애플리케이션이 가장 갈증을 느끼는 리소스라서 CPU의 효율적 사용은 성능 향상의 지름길

  • vmstat

    vmstat 1은 스냅샷을 한번만 찍는 게 아니라 1초마다 한번씩 찍어 다음 줄에 결과를 표시

튜닝이 잘 된 프로그램은 리소스를 최대한 활용

CPU 사용률이 100%에 근접하지 않았다면 ‘왜 그럴까?’ 따져봐야 함

대다수 OS에서 vmstat은 컨텍스트 교환 발생 횟수를 나타내므로 vmstat 1 명령을 실행하면 컨텍스트 교환의 실시간 영향도를 지켜볼 수 있다

유저 공간에서 CPU 사용률이 100% 근처도 못 갔는데 어떤 프로세스에서 컨텍스트 교환 비율이 높게 나타나면 I/O에서 블로킹이 일어났거나, 스레드 락 경합 상황이 벌어졌을 공산이 크다

3.6.2 가비지 수집

어떤 시스템에서 CPU 사용률이 높게 나타난다면, GC는 대부분의 시간을 소비하는 주범이 아님

GC 자체는 유저 공간의 CPU 사이클을 소비하되 커널 공간의 사용률에는 영향을 미치지 않기 때문

반면, 어떤 JVM 프로세스가 유저 공간에서 CPU를 100% 가깝게 사용하고 있다면 GC를 의심해야 함

JVM에서 GC 로깅은 거의 공짜나 다름 없다

GC 로깅은 분석용 데이터의 원천으로서도 가치가 높기 떄문에 JVM 프로세스는 예외 없이, 특히 운영 환경에서는 GC로그를 꼭 남겨야 함

3.6.3 입출력

파일 I/O는 예로부터 전체 시스템 성능에 암적인 존재

커널 바이패스 I/O

커널 대신 직접 네트워크 카드에서 유저가 접근 가능한 영역으로 데이터를 매핑하는 전용 하드웨어/소프트웨어 사용

이렇게 하면 커널 공간과 유저 공간 사이를 넘나드는 행위 및 이중 복사를 막을 수 있다.

그러나 자바는 기본적으로 이와 관련된 구현체를 제공하지 않으므로 필요한 기능을 구현하려면 커스텀(네이티브) 라이브러리를 써야 힌다

3.6.4 기계 공감

기계 공감은 성능을 조금이라도 쥐어짜내야 하는 상황에서 하드웨어를 폭넓게 이해하고 공감할 수 있는 능력이 무엇보다 중요하다는 생각

기계 공감은 자바 개발자가 무시하기 쉬운 관심사

고성능, 저지연이 필수인 분야에서 개발자가 자바/JVM을 효과적으로 활용하려면 JVM이란 무엇이고, 하드웨어와는 어떻게 상호작용하는지 이해해야 함

3.7 가상화

가상화는 이미 실행 중인 다른 OS(호스트 OS) 위에서 OS 사본(게스트 OS)을 하나의 프로세스로 실행시키는 모양새가 보통

가상화의 특징

  • 가상화 OS에서 실행하는 프로그램은 베어 매탈(즉, 비가상화 OS)에서 실행할 때와 동일하게 작동해야 한다
  • 하이퍼바이저는 모든 하드웨어 리소스 액세스를 조정해야 한다
  • 가상화 오버헤드는 가급적 작아야 하며 실행 시간의 상당 부분을 차지해선 안 된다

대개 프리빌리지드 명령어를 언프리지빌리지드 명령어로 고쳐 씀

3.8 JVM과 운영체제

JVM은 자바 코드에 공용 인터페이스를 제공하여 OS에 독립적인 휴대용 실행환경을 제공

하지만 스레드 스케줄링 같은 아주 기본적인 서비스조차도 하부 OS에 반드시 액세스해야 함

이런 기능은 native 키워드를 붙인 네이티브 메서드로 구현 -> 자바 네이티브 인터페이스(Java Native Interface, JNI)

참조

  1. Optimizing Java(자바 최적화)
This post is licensed under CC BY 4.0 by the author.