• 성능이란?
    • 성능은 실험과학이다 → 테스트와 데이터 없이는 의미가 없다
    • 분류
      • 처리율: 일정 시간 동안 완료한 작업 단위 수
      • 지연: 하나의 트랜잭션을 끝까지 처리하는데 소요된 시간
      • 용량: 특정 처리율/지연값을 전제로 가능한 처리량
      • 사용률: 시스템 리소스의 사용량
      • 효율: 처리율/사용률
      • 확장성: 리소스 추가에 따른 처리율의 변화
      • 저하: 풀 가동된 시스템에서 처리율이 늘어나지 않고 지연이 증가하는 정도
    • 성능 엘보: 부하가 증가하면서 예기치 않게 저하가 발생하는 지점
  • JVM
    • 스택 기반의 해석 머신
    • 클래스 로드 순서: 부트스트랩 → 확장 클래스 → 어플리케이션 → 디펜던시
      • 부트스트랩: 자바 런타임 코어 클래스 로드 → 최소한의 필수 클래스만 로드
      • 확장 클래스: 부트스트랩을 부모로 설정하고 네이티브 코드/ 기본 환경 오버라이드 등을 수행
      • 어플리케이션: 클래스패스에 위치한 유저 클래스 로드 ( 확장 클래스의 자식)
      • 디펜던시: 처음 보는 새 클래스 로드.
    • JIT 컴파일
      • 핫스팟 JVM이 인터프리티트 바이트 코드의 일부를 네이티브로 컴파일하여 수행하는 방식
      • 자주 실행되는 메서드를 최대한의 성능으로 수행하기 위해 구현
      • 동적 인라이닝, 가상 호출 등의 기술로 런타임의 더 좋은 성능 향상이 가능
    • GC: 더 많은 메모리를 할당해야 할 때 불필요한 메모리를 회수하거나 재 사용하는 불 확정적 프로세스
    • JMM: 서로 다른 스레드가 객체 안에 변경되는 값을 어떻게 바라보는지에 대한 공식 메모리 모델
  • 최신 하드웨어와 운영체제
    • TLB(변환 색인 버퍼): 가상 메모리 주소를 물리 메모리 주소로 맵핑하는 페이지 테이블의 캐시
    • MMU(메모리 관리 유닛): 한 프로세스가 소유한 메모리 영역을 다른 프로세스가 훼손하지 못하게 하기 위해 가상 주소 방식과 페이지 테이블을 이용
    • 컨텍스트 교환
      • OS 스케쥴러가 현재 실행 중인 스레드/태스크를 없애고 대기중인 다른 작업으로 교체하는 프로세스
      • 캐시가 무효화되고 매우 비싼 작업
  • 성능 테스트 팁
    • 성능 지표를 수집 및 분석해야만 문제의 본질을 알 수 있다
    • 쉬운게 아니라 중요한 부분을 테스트해야 한다
    • 화려함(새로운 기술)등에 사로잡히지 말아야 한다
    • 성급하게 문제를 판단하려 들지 말야하 한다 → 특정 기술, 컴포넌트를 의심하는 행위
    • 민간 튜닝 금지 → 특히 인터넷을 통한 검색만으로 테스트 없이 적용하는 행위
    • UAT(인수 테스트 장비)는 최대한 운영계 데이터와 유사하게 맞추어야 한다
    • 환원 주의에 빠지지 말고 전체 시스템을 봐야한다
  • 마이크로 벤치마킹과 통계
    • 마이크로 벤치마킹: 작은 자바의 코드 조각을 테스트하는 것
    • 정확한 측정을 하기는 매우 어려우나 JMH와 같은 표준툴이 존재한다
    • 범용 라이브러리나 극도의 저지연 코드가 필요할 때만 사용하는 것이 좋다
    • 평균의 함정에 속지 말자 ( P50, 95, 99 와 같은 값이 더 정확하다 )
  • GC
    • 시스템이 모든 객체의 수명을 정확히 몰라도 런타임이 대신 객체를 추적하며 쓸모없는 객체를 제거하는 것
    • 반드시 모든 가비지를 수집해야 하며 살아있는 객체는 절대 수집해서는 안된다
    • 순전히 필요에 의해서 불확정/불규칙적으로 발생한다
    • 할당 리스트: 할당되었지만 아직 회수되지 않은 객체 포인터를 포함한 리스트
    • 프리 리스트: 할당되지 않은 공간을 나타내는 리스트
    • STW: 가비지를 수집하는 동안 모든 어플리케이션 스레드가 중단되는 현상
    • GC 루트: 메모리의 고정점으로 메모리 풀 외부에서 내부를 가리키는 포인터
    • 조기 승격: 영 세대의 할당률이 너무 높아 GC 카운트를 쉽게 넘어 Old 영역으로 너무 많이 넘어가는 현상
    • Mark And Sweep
      • GC의 기본 알고리즘
      • 순서
        • 할당 리스트에 모든 마크비트를 제거한다
        • GC 루트로부터 살아있는 객체를 찾고 마크비트를 세팅한다
        • 할당 리스트에서 마크비트가 없는 객체를 삭제하고 프리리스트에 되돌린다
    • 약한 세대별 가설
      • GC 구현의 기반 이론으로 거의 대부분의 객체는 매우 짧은 시간만 살아있지만 나머지는 기대 수명이 훨씬 길다는 가설
      • 카드 테이블: 늙은 객체가 젊은 객체를 참조하는 정보를 기록하는 바이트 배열
      • 구현
        • 객체마다 가비지 수집에 통과한 횟수를 기록한다
        • 큰 객체를 제외한 나머지는 Eden에 생성하고, 여기서 살아남은 객체는 다른 공간(Survivor)로 이동한다
        • 충분히 오래 살아남은 객체는 Old(Tenured)에 이동하여 보관한다
    • 스레드 로컬 할당 버퍼(TLAB)
      • Eden을 여러 버퍼로 나누어 각 어플리케이션 스레드가 개별적으로 새 객체를 할당하는 구역으로 활용
      • 이를 통해 스레드가 객체를 할당하는 시간을 O(1)로 줄일 수 있다
    • 반구형 수집(Survivor)
      • 실제로 장수하지 못할 객체를 임시 수용소 2개에 담는 전략
      • 단명 객체가 Old 공간을 어지럽지 않게 하여 Full Gc 발생을 줄인다
      • 수집할 때 객체들을 다른 반구에 압착시켜 옮기고 수집된 반구를 비워서 재사용한다 ( 항상 반은 비어있음 )
    • JVM 세이브 포인트
      • 스레드마다 존재하는 내부 자료가 보이는 지점으로 여기서 스레드는 잠시 중단이 가능하다
      • STW에 의해 어플리케이션 스레드가 망가지는 것 방지하기 위함
      • 생성 장소: 루프 백 브랜치, 메서드 반환부
    • 병렬 수집기
      • 처리율에 최적화되어 있으나, young/full GC 모두 STW를 일으킨다
      • 스냅샷 뜨기(SATB)
        • 수집 사이클을 시작할 때 접근 가능하거나 그 이후 할당된 객체를 라이브 객체로 간주하는 방식
        • 삼색 마킹 이론과 쓰기 배리어를 통해 병렬 수집이 가능하게 한다
      • 종류
        • Parallel: 가장 단순한 young 수집기. 4GB이하에서 매우 유용 ( JDK 8 기본 GC)
        • ParNew: CMS와 함께 사용할 수 있게 Parallel을 변형한 수집기
        • ParallelOld: full Gc용 수집기
          • 하나의 연속된 공간에 압착하여 단편화를 없애는 작업을 추가로 함
          • STW 시간이 힙 크기에 비례한다
        • CMS(concurrent mark sweep) 수집기
        • G1 수집기
        • 셰넌도어 수집기
        • 엡실론 수집기: 아무 일도 하지 않는 테스트용 수집기
    • 로깅
  • JVM 코드 실행
  • JIT 컴파일
  • 언어 성능 향상 기법
  • JMM 과 동시성
  • 프로파일링과 고성능 로깅
  • java의 미래

  • 최신 JVM은 가상 디스패치조차도 콜 사이트에서 없애고 자동 인라이닝을 도입하면서 성능 개선을 이루었다
  • java에서 클래스로더는 하나의 객체에 불가하기 때문에 main method를 이용한 초기 세트를 존재하게 할 방법이 필요하다
  • 자바에서 native 키워드가 붙은 함수는 OS에 반드시 액세스해야 하는 작업이다
  • 멀티스레드 환경
  • 오프힙: 힙이 아닌 네이티브 메모리 영역( 자바의 다이렉트 버퍼와 유사 )
  • 콜드 케이스: 원인을 알 수 없는 현상