Page tree
Skip to end of metadata
Go to start of metadata
  1. 구조

    1. class loader

      컴파일된 자바 바이트 코드를 런타임 데이터 영역에 로드

    2. execution engine

      런타임 데이터 영역에 로드된 자바 바이트 코드 실행.

    3. runtime data areas

      런타임 데이터 영역은 JVM에게 할당받는 메모리 영역으로 아래와 같이 6개의 영역으로 나눌 수 있음.

      쓰레드 별로 할당받는 영역들PC Register 현재 수행중인 JVM 명령의 주소를 가짐.
      Native Method Stack 자바 외의 언어로 작성된 네이티브 코드를 위한 스택이다. 즉, JNI(Java Native Interface)를 통해 호출하는 C/C++ 등의 코드를 수행하기 위한 스택으로, 언어에 맞게 C 스택이나 C++ 스택이 생성된다.

      JVM Stack 스레드가 라이프 사이클 주기에 맞춰 생성되고 소멸되며 스택 프레임이란 구조체를 저장하는 스택. JVM 은 오직 JVM 스택에 스택 프레임을 추가하고 제거하는 동작만 수행. - 스택 프레임 JVM 내에서 메서드 수행될때마다 하나의 스택프레임이 생성되며 해당 스택프레임에는 지역변수배열, 피연산자스택, 해당 메소드 실행되는 클래스 상수 정보 등을 가진 런타임 풀 레퍼런스를 가진다.
      (런타임 풀 레퍼런스에는 클래스의 메서드와 필드에 대한 모든 레퍼런스를 담고 있기때문에 JVM은 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리상 주소를 찾아 참조한다.)

      독자적으로 할당받는 영역들Heap 인스턴스 또는 객체를 저장하는 공간으로 가비지 컬렉션 대상이 되며, 곧 성능 이슈를 일으키는 공간이다.
      Method Area JVM 이 시작될 때 생성되는 공간으로 JVM이 일어들인 각각의 클래스와 인터페이스에 대한 런타임 상수 풀, 필드와 메서드 정보, static 변수, 메서드의 바이트 코드등을 보관한다. 흔히 Permanenet Area, Permanant Generation(PermGen) 이라 불린다. 가비지 컬렉션 대상 여부는 선택사항.

      PermGen 이라 보통 표현되는 이 영역은 클래스의 모든 정보를 가지고 있는 영역이며, 특별히 가비지 컬렉션 대상으로 설정하지 않는 한 지속적으로 그 영역이 커진다.
      (자바는 클래스를 로드할 때에 미리 모든 정보를 로드하는 것이 아니라 런타임으로 로드를 하기때문에 특정 클래스가 참조될 때에 PermGen 에 해당 클래스 정보가 없을시
      그때에 PermGen 영역에 해당 클래스 정보를 로드하고 이를 활용하여 객체를 생성하며 Heap 에 적재한다.)

      매우 중요한 영역이라 그런지 Java 8 에서 부터는 metaspace 라는 이름으로 대체되었으며 PermGen 영역이 사라졌다.
      (아래 세번째 참고에 보면 static object, class, method meta data 의 증가(hot deploy 로 인한 클래스 정보 적재) 등의 사유로 해당 영역을 없앤 것으로 추정.)
      Java 8 의 메모리는 간략하게 아래에 정리.
      Runtime Constant Pool 각 클래스와 인터페이스의 상수, 메서드와 필드에 대한 모든 레퍼런스를 담고 있는 테이블로 메서드나 필드의 실제 메모리상 주소를 찾을땐 해당 풀을 참조한다.

      참고 : http://d2.naver.com/helloworld/1230
      https://blogs.oracle.com/jonthecollector/presenting-the-permanent-generation
       
      https://yckwon2nd.blogspot.kr/2015/03/java8-permanent.html
       
      https://stackoverflow.com/questions/2129044/java-heap-terminology-young-old-and-permanent-generations

       

  2. JVM Heap with jvm option

    heapedenminor gc (gc 시간 상대적 짧음)Young Gen최초 객체 생성시 상주되는 메모리로 가장 빠르게 gc 를 맞는 영역이다.
    s0survivor 영역이라 하며, eden 영역에서 minor gc 발생시점에 살아남은 객체가 두 영역 중 하나로 이동하게 된다.
    계속된 eden 영역에서의 minor gc 이후 살아남은 객체들이 하나의 영역을 채우게 되면, 거기서 살아남은 객체들에 대해 다른 나머지 영역으로 이동을 하게 된다. 이 과정이 반복되는 영역이다.
    s1
    old memorymajor gc (gc 시간 상대적 김)Old Gen위 survivor 영역에서의 swap 이 반복된 이후에도 살아남은 객체들은 old memory 로 이동하고 major gc의 대상이된다.

    jvm option (추려낸)

    -XmsJVM 시작시의 Heap size  
    -Xmx최대 Heap size  
    -XX:PermGenJVM 시작시의 Method Area size (PermGen)java 8 에서 제거 
    -XX:MaxPermGen최대 Method Area sizejava 8 에서 제거 
    -XX:SurvivorRatioYoung Gen 영역의 비율 (eden : s0 + s1)
    Xmn / (SurvaivorRatio + 2) = 각 survivor size
    (Xmn / (SurvaivorRatio + 2)) * SurvaivorRatio = eden size
    만약 Xmn = 10M 이라면
    eden : 5M, s0 : 2.5M, s1 : 2.5M
      
    -XX:NewRatioeden : Old Gen 비율 (비율 기준은 Old 가 가짐)
    NewRatio = 2 라면 eden 1 : old 2
      
    -XX:NewSizeeden 영역의 사이즈  

    참고 : http://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java,
    http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html,
    https://stackoverflow.com/questions/2129044/java-heap-terminology-young-old-and-permanent-generations

  3. GC

    1. GC 가 하는 역할.

      1. Heap 내의 객체 중에서 garbage 를 찾아낸다.
      2. 찾아낸 가비지를 처리해서 힙의 메모리를 회수한다.
      JVM 의 GC 에서 메모리 정리는 따로 쓰레드로 동작하고 있다.


    2. GC 종류 (아래 표에 정리)

    3. GC 전략
      1. throughput vs response time trade-off
        1. 일반적으로 web service 에서는 throughput 중심의 튜닝이 필요하다.
          1. 응답시간을 조금 줄이더라도 GC 발생을 억제.
          2. parallel algorithm
            1. 여러개 쓰레드 가 full gc 를 최대한 빨리 끝낸다.
            2. CMS 에 비하여 안정성 높음
          3. concurrent algorithm (cms)
            1. 여러 쓰레드 + 실시간 mark & sweep => full gc방지
            2. cpu 자원이 가장 많이 필요하다.
            3. 메모리 파편화에 따른 무한 full gc발생 등의 안정성 문제
          4. g1
            1. 메모리 영역을 순차적으로 관리하지 않고 특정 크기 단위의 region 이라는 블럭을 사용하며 compact 를 배제
            2. GC의 발생을 줄이면서 GC 수행시간을 개선함
            3. Xmx 2G 이하에서는 오히려 overhead 발생 등으로 안좋을 수 있다.
 optionYoung GenOld GenGC 방식장 / 단점
Serial GC-XX:+UseSerialGCgeneration algorithmmark-compact-algorithm1) old 살아있는 개체 식별(mark)
2) heap 앞부분부터 확인해 살아있는것만 남김(sweep)
3) 각 객체들이 연속되게 쌓이도록 heap 의 가장 앞 부분부터 적재(compact)

 

적은 메모리와 단일 코어

서버운용으론 불가
STW 시간 소요

 

Parallel GC-XX:+UseParallelGC 
-XX:ParallelGCThreads=value
generation algorithm
(multiple thread)
mark-compact-algorithm

serial GC 와 동일하나 Young Gen 을 병렬처리

serial GC 보단 빠르나
많은 메모리와 코어 갯수가 많을 때나 유리
STW 시간 소요
Parallel Old GC-XX:+UseParallelOldGCgeneration algorithm
(multiple thread)
parallel compactiong algorithm
(mark-summary-compaction)

Serial GC 를 기본으로 수행을 하지만,
compaction 단계 이전에 summary 라는 단계를 가진다.
해당 작업에서는 이전 GC 이후의 메모리를 인덱싱하는 작업을 우선 수행하고
해당 인덱스가 마무리된 메모리에 compact 작업을 수행하게 된다.
공간에 대한 인덱싱 작업때문에 약간의 메모리를 더 소모할 수 있다.

참고 : https://stackoverflow.com/questions/20430058/parallel-compacting-collector-algorithm

Parallel 의 장점을 가져가고,

동시에 old 영역에 대한 GC 처리량도 늘림
약간의 메모리 소모가 더 발생할 수 있다.

CMS
(Concurrent Mark-Sweep)
-XX:+UseConcMarkSweepGC 
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=value
-XX:+UseCMSInitiatingOccupancyOnly
parallel copy algorithmconcurrent mark-and-sweep algorithm1) ROOT set 에 의해 직접 참조되는 객체들을 Marking (initial mark)
2) 애플리케이션 동작 중 작업하며 살아있는 객체 식별 (concurrent mark)
3) 2번에서 새로 추가로 참조가 끊긴 객체를 확인 (remark)
4) 참조가 끊긴 모든 쓰레기 정리 (concurrent sweep)
모든 작업은 독립 쓰레드가 병렬로 처리.
compact 단계는 기본으론 제공하지 않음.
애플리케이션 응답속도가 매우 빠르다.

다른 GC 보다 메모리와 CPU 를 많이 사용,
Compact 단계가 없다. (살아있는 객체에 대해 메모리 정리하는 작업)
Compact 단계가 존재하지 않아 조각난 메모리가 많다. (메모리의 단편화)
자칫 위의 사유로 무한 Full GC 발생 가능
G1 GC-XX:+UnlockExperimentalVMOptions
-XX:+UseG1GC
evacution pauseconcurrent marking
  • new, old 영역에 연속된 메모리 주소에 대한 구조적 개념을 배재, 메모리 영역을 통으로 관리.
  • 전체 메모리를 Region 이라 부르는 블럭 형식 단위로 분할하고 이 영역에 객체를 할당
    • XX:G1HeapRegionSize=size 로 블럭단위 설정 가능.
    • JDK6 u26 에서는 init heap size / 2048 이 기본 단위.
  • 기존의 메모리 할당(new => old) 을 promotion 이라 칭했는데 이를 G1 에서는 Evacuation 이라 칭함.
  • 내부적으로 GC동작에 대한 기준은 STW 시간에 대한 목표치를 기반.
    • XX:MAXGCPauseMillis=<n>, 기본값 : 200ms
  • 전체 region 을 대상으로 객체 referrer 를 참조하는 card table 소지.(card table 은 old 객체가 현재 참조중인 new 객체에 대한 메모리 주소를 관리, 이를 Remembered Sets 이라 한다.)
  • GC 가 시작되면 Young region 정리(minor gc) 후 evacuation 과 compation (major gc) 가 연속으로 진행된다.

1) G1 으로 설정한 JVM 은 New/s0,1/old 로 구분되는 물리적 메모리 구분없이 region 으로 불리는 메모리블럭을 구성하면서 기동 (논리적으로 구분되어있지만, 물리적 구분 없음)

2) 초기 구동시에 생성되는 객체들은 임의의 region 에 생성되며 해당 객체의 referrer 정보는 remembered set 에 저장.
3) young gc (minor gc) 수행은
a. remembered set referrer 정보를 참조하여 살아있지 않는 것만 마킹하며 싱글스레드로 진행
b. region 의 살아있는 객체 밀도가 낮은 region 에 대해 evacuation 진행
정리대상에 region 내에 살아있는 객체는 다른 region으로 복사되며 나머지 폐기
4) old gc (major gc) 수행은
a. young gc 의 evacuation와 동일하게 진행
b. 이때 메모리가 부족하거나 GC 수행시간이 설정보다 길어질것으로 판단되면, GC 를 다시 수행하면서 survivor, old 영역으로 지정된 region 들이 메모리 앞쪽으로 정리하는 compation 단계를 거침. (region 단위로 이동)

server style gc 라고 불림.

region 들의 referrer 를 관리하기 위한 overhead 존재로 Xmx 2G 이상의 heap 메모리 요구

각 JDK 별 기본 GC

  • Java 7 - Parallel GC
  • Java 8 - Parallel GC
  • Java 9 - G1 (proposed)

 

  • No labels

1 Comment

  1. GC 모니터링은 따로 정리를 안했습니다.

    사실 위 자료도 짜집기 수준이지만, 모니터링에 대해서는 워낙 괜찮은 상용 APM 이 많고, 무료 툴도 있고, 잘 정리된 자료도 있어 정리를 안했습니다. (귀찮음을 이렇게 장황하게 적어보았습니다.)

    때문에 잘 정리된 문서만 링크해보도록 하겠습니다!

    http://d2.naver.com/helloworld/6043