ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JVM( GC) 이해하기
    Java/Basic 2019. 4. 26. 17:00
    반응형

    GC

     자바에서 가비지 콜렉터는 가장 중요한 기능중 하나다 자바 GC 만큼 역사와전통(?) 을 자랑하는 것도 없을거 같다. 기본적으로 C 언어계열들과 차이를 들때(예전... 2000년대 초반.. ) 메모리를 C 계열은 직접 프로그래머가 해줘야 하지만 자바는 JVM 이 알아서 해준다 였다. GC가 그 메모리를 알아서 관리 해주는 녀석이다. 

     

    GC 란?

     자바는 앞서 말했듯이 GC 라는 알고리즘을 통하여 자동 관리 하기 때문에 개발자 메모리를 처리하기 위한 로직이 없고 만들어서도 안된다. 

     가비지 컬렉터는 자바에서 버리는 객체들을 관리 한다. 하나의 객체를 생성할경우 그에 맞게 메모리가 할당되어 메모리를 점유하게 되고 필요하지 않는경우 메모리를 해제 해야만 메모리누수가 없게 된다. 

     그렇기 때문에 가비지 컬렉터는 객체가 메모리가 할당되고 모든 작업을 수행뒤 더이상 할일이 없는 상태의 객체가 될경우 이 객체를 청소하는 작업을 한다. 

     

    GC 원리 

     

    1. 메모리 할당

     2. 사용중인 메모리 인식

     3. 사용하지 않는메모리 인식

     

    가비지 컬렉터가 동작을 하고 있으나 더이상 사용가능한 메모리가 없는 상태에서 더 메모리 할당을 할경우 OutOfMemoryError 가 발생하여 JVM 이 다운될수도 있다. 서버 혹은 jvm 기반의 어플리케이션이 처리를 못하고 있거나 과도하게 메모리가 할당된 상태가 된다. 

     JVM 은 크게 메모리 영역을 클래스,스택,힙,네이티브 메소스 스택 4개영역으로 나누고 가비지 컬렉터는 주로 힙메모리를 관리하게 된다. 가비지 컬렉터가 관리 하는 힙메모리는 다시 young, old , perm 세영역으로 나누어 관리하는데 perm 영역은 거의 사용하지 않는영역으로 클래스와 메소드 정보와 같이 자바 언어레벨에서 사용되지 않는다. 

     Young 영역은 Eden, survivor 두가지로 나눈다.

     

    먼저 메모리에 객체가 생성되면 Eden  영역에 생성이 되고 어느정도 데이터가 쌓이면 eden 영역에 생성된 객체는 삭제되거나 survivor 영역으로 이동되게 된다.  survivor 영역에 할당되고 어느정도 survivor  영역이 차면 GC 동작하면서 eden 영역에 있는 객체와 survivor 영역에 있는 객체가  비어있는 survivor  영역으로 이동하게 되며 더이상 Young 영역에 공간이 남지 않으면 Old 영역으로 이동한다. 

     

    GC 종류 

     

    마이너 GC : Young 에서 발생하는 GC

    메이저 GC : Old 이나 Perm 에서 발생하는 GC

     

    GC 방식 

     

    1. Serial Collector ( 시리얼 콜렉터 )

    2. Parallel Collector ( 병렬 콜렉터 )

    3. Concurrent Mark-Sweep(CMS) Collector ( cms 콜렉터 )

    4. G1 Collector

     

     

    1. 시리얼 콜렉터 

     

    시리얼 콜렉터 명시적 지정 방법

       -XX:+UseSerialGC

     

    가장 단순한 GC , 단순무식하게 Young 영역을 정리하는 마이너 GC 때도 stop-the-world , Full GC 때도 올스탑상태에서 정리를 함. 단순 클라이언트 어플리케이션에서 사용하면 적합한 GC 


     Young 과 old 영역이 연속적으로 처리 되며 하나의  CPU 를 사용. Stop-the-world 로 표현. 콜렉션이 수행되면 어플리케이션수행이 정지됨 

     순서 : eden -> survivor or old -> 여유 survivor -> eden, survivor  남아있는  객체를 old 영역 으로 이동

    모든순서대로 진행이후 old 영역이나 perm 영역의 객체들은 Mark-sweep-compact 콜렉션 알고리즘에 따라 동작

    안쓰는거 표시해서 삭제하고 한곳으로 모으는 알고리즘 이다. 

     

     * Mark-sweep-compact 알고리즘

    1) Old 영역으로 이동된 객체들 중 살아 있는 개체를 식별합니다. (Mark)

    2) Old 영역의 객체들을 훑는 작업을 수행하여 쓰레기 객체를 식별합니다. (Sweep)

    3) 필요 없는 객체들을 지우고 살아 있는 객체들을 한 곳으로 모은다 (Compact)

    출처: https://12bme.tistory.com/57 [길은 가면, 뒤에 있다.]

     

     

    2. 병렬 콜렉터 

     

    병렬 콜렉터 명시적 지정 방법

       -XX:+UseParallelGC

     

    마이너 GC 와 풀 GC 모두 멀티쓰레드 기반으로 동작하여 속도가 더 빠르다. 하지만 풀 GC 일때 stop-the-world 인건 동일하다.

     

     이 방식은 CPU 가 대기상태로 있는것을 최소화 한다. 콜렉션을 병렬 처리를 한다. 그렇기 때문에 많은 CPU를 사용하게 된다. GC 의 부하는 줄이고 어플리케이션의 처리량을 증가 시킬수 있다. 

     Old 영역의 GC는 시리얼 콜렉터와 마찬가지로 Mark-Sweep-Compact 콜렉션 알고리즘을 사용한다.

     

    3.CMS 콜렉터 

     

     CMS 콜렉터 명시적 지정방법

       -XX:+UseConcMarkSweepGC

     

    기본적으로 병력 콜렉터와 동일하게 GC 를 한다. 그리고 stop-the-world 도 동일하게 발생하지만 풀GC 때에는 거의 발생하지 않는다. 이유는 어플리케이션이 동작중에 백그라운드에서 쓰레드를 만들어서 Old 영역에 쓰레기 객체들을 지속적으로 제거한다. 그렇기 때문에 가장 큰 장점은 stop-the-world 가 거의 없다는것이고 마이너 GC 에서 잠깐식 발생한다는것이다. 

     하지만 단점으로는 백그라운드로 돌아야하다보니 기본 CPU 사용률이 놓고 중간에 Old 영역을 주기적으로 지우면서 메모리가 군데군데 비어져서 메모리 파편화가 발생한다. 그리고 파편화가 심해져 메모리 여유가 없어지면 Serial GC 가 하는 방식 그대로 동작한다.  Old 영역을 싱글 쓰레드로 청소한다. 

     

      1) Mark 단계 : 매우 짧은 대기 시간으로 살아 있는 객체를 찾는 단계

      2) Sweep 단계 : 서버 수행과 동시에 살아 있는 객체에 표시를 해 놓는 단계

      3) Remark 단계 : Concurrent 표시 단계에서 표시하는 동안 변경된 객체에 대해서 다시 표시하는 단계

      4) Concurrent Sweep 단계 : 표시되어 있는 쓰레기를 정리하는 단계


    CMS는 컴팩션 단계를 거치지 않기 때문에 왼쪽으로 메모리를 몰아 놓는 작업을 수행하지 않는다. 그래서 GC 이후에 그림과 같이 빈 공간이 발생하므로, -XX:CMSInitiatingOccupancyFraction=n 옵션을 사용하여 Old 영역의 %를 n 값에 지정한다.(기본값 : 68)
     CMS 는 2개이상의 프로세서를 사용하는 서버에 적합하다. 대표적으로 웹서버가 있다. 

    CMS 콜렉터는 점진적 방식을 사용가능한 추가적인 옵션들을 지원한다. 이옵션들은  Young 영역의 GC 를 더 잘개 쪼개어 수행하도록 하여 서버 대기시간을 줄일수 있다. 서버에 CPU가 많지 않고 시스템의 대기시간이 짧아야 할때 사용하면좋다. 점진적은 GC를 수행하려면 -XX:+CMSIncrementalMode 옵션을 지정하면 된다. JVM에 따라서는 -Xingc라는 옵션을 지정해도 같은 의미가 된다. 하지만 이옵션을 사용할경우 GC 가 너무 자주 발생하는 경우가 생겨 오히려 성능에 저하가 생길수 있다. 충분한 테스트 후 사용 해야한다. 

    4. G1 컬렉터

     

    G1 컬렉터 명시적 지정방법

     XX:+UseG1G

     

    힙영역이 매우 큰 머신에서 돌리기 좋은 GC 이다. CMS 의 단점을 어느정도 보완했다. 

    힙을 여러개의 region 으로 나눈뒤 몇몇은 Young 영역으로 쓰고 나머지 몇 Region 은 Old 영역으로 사용한다. 

    Young 영역은 parallel 이나 cms 처럼 멀티쓰레드 방식으로 정리하고 Old 영역에 해당되는 Region이 여러개 있을텐데 cms 처럼 백그라운드 쓰레드로 이영역들을 정리한다. 단, 여기서 CMS 와 다른것은 영역의 일부를 정리하는것이 아니라 Region 을 통으로 정리한다. 참조가 없는 객체들은 모두 지우고 사용중인 객체는 다른 Region으로 복사한뒤 통으로 정리한다.  이 객체를 옮기는 과정에서 차곡차곡 옮기기 때문에 Compacting 이 되어 파편화 현상을 방지한다.

     CMS 에서 문제가 되었던 CPU 리소스를 많이 사용/ 메모리파편화 문제를 해결한 버전이다. 

     


    GC 를 잘쓰려면 
     1) 기본적으로 메모리의 허용치를 넘을때

     

     개발자가 컨트롤하기엔 영역을 넘어서는같다.  개인적으로는 힙메모리 정도는 옵션으로 주는경우는 보았지만 GC 까지 튜닝해서 사용하는경우는 못봤으며 서버 세팅을 하진 않았던것 같다. 그렇지만 이해는 하고 있어야 하며 대학생이라면 시험에 나올수도 있고 현역프로그래머라면 이직할때 물어 볼지도 모르기 때문에 알고는 있어야 한다고 본다. 

     

     네이버 기술블로그였던거 같지만 거기에 가비지컬렉터에 대한 튜닝 여유에 대해서 글시작부터 나오는 말이있다. 

     

     "모든 Java 기반의 서비스에서 GC 튜닝을 해야 할까?"

      결론부터 이야기하면 모든 Java 기반의 서비스에서 GC 튜닝을 진행할 필요는 없다.

     

    나도 동감하는 말이다!! 최악의 최후에나 고려해봐야 하지 않을까...

    반응형

    'Java > Basic' 카테고리의 다른 글

    Logback 시간과 system 시간이 다를때...  (0) 2019.06.25
    BigDecimal (feat. 소수점 계산)  (1) 2019.03.26
    [java] Http get,post 통신  (0) 2019.01.28
    [java]날짜 더하기, 빼기 , 구하기  (0) 2019.01.28
Designed by Tistory.