ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java 버전 별 차이 & GC(Garbage Collector)
    Java 2023. 7. 9. 20:46

     

    들어가기 전에

    Java 언어를 주로 사용하며 개발하고 있지만 지속적으로 업데이트되는 버전 별 차이를 파악해보는 시간을 가져보고 자바의 메모리 관리 방법 중 핵심인 가비지 컬렉터를 알아보려고 한다.

     

    Java 버전 차이

    Java 1.0(1996.01.23)

    : 첫 번째 공식 Java 버전으로, 기본적인 Java 플랫폼이 발표되었다. 이 버전에서는 Java 가상 머신(JVM) 및 Java 개발 도구가 포함

     

    Java 1.1(1997.02.19)

    : 이 버전에서는 내부적인 개선과 성능 향상이 이루어졌습니다. 이벤트 처리 모델과 AWT(Abstract Window Toolkit)의 업데이트, 내장 자료구조 및 API의 확장이 주요 변경 사항

     

    Java 1.2(1998.12.08)

    : 이 버전에서는 Java 플랫폼이 대대적으로 개선되었다. Swing API의 도입으로 그래픽 사용자 인터페이스(GUI) 개발이 향상되었고, 컬렉션 프레임워크가 도입되어 자료구조와 알고리즘을 표준화

     

    Java 1.3(2000.05.08)

    : 이 버전에서는 성능 개선과 GUI 개선을 중점으로 하였다. HotSpot 가상 머신이 도입되어 성능이 향상되었고, Java Sound API 와 Java Naming and Directory Interface(JNDI)의 개선

     

    Java 1.4(2002.02.06)

    : 이 버전에서는 XML 처리, 자바 웹 스타트(Java Web Start), 스레딩 개선 등의 기능이 추가되었다. 또한, assert 키워드가 도입되어 디버깅을 보다 쉽게 할 수 있게 되었다.

     

    Java 5(2004.09.30)

    : 이 버전에서는 가장 중요한 변화 중 하나인 제네릭스(Generics)가 도입되었다. 또한, 열거형(Enum), 자동 박싱/언박싱(AutoBoxing/Unboxing), 가변 인자(Varargs) 등의 기능이 추가되었다.

     

    Java 6(2006.12.11)

    : 이 버전에서는 성능 향상과 보안 개선이 주요 목표였다. Java Compiler API, 플러그 가능 주석(Pluggable Annotation) 등의 기능이 추가되었고, Scripting API 가 도입

     

    Java 7(2011.07.28)

    : 이 버전에서는 다이아몬드 연산자(Diamond Operator), 문자열 스위치(String Switch), Try-with-resources 등의 기능이 추가되었다. 또한, NIO(Non-blocking I/O)의 개선과 다중 예외 처리(Multi-catch Exception Handling)가 도입

     

    Java 8 LTS(2014.03.18)

    : 이 버전에서는 가장 큰 변화 중 하나인 람다식(Lambda Expressions)이 도입되었다. 스트림(Streams) API, 날짜 및 시간 API, 디폴트 메서드(Default Methods) 등의 기능이 추가

     

    Java 9(2017.09.21)

    : 이 버전에서는 모듈 시스템이 도입되었다. JShell(대화형 프로그래밍 쉘)이 추가되었고, HTTP/2 및 REPL(Read-Eval-Print Loop)을 지원하는 새로운 도구인 JLink, JShell, JImage 등이 도입

     

    Java 10(2018.03.20)

    : 이 버전에서는 지역 변수 유형 추론(Local Variable Type Interface)이 도입되었다. 또한, 스레드 로컬 핸드쉐이크(Thread-Local Handshakes)와 개선된 GC(Garbage Collector)가 추가

     

    Java 11 LTS(2018.09.25)

    : 이 버전에서는 모듈 시스템과 관련된 개선이 이루어졌습니다. JavaEE(Enterprise Edition) 모듈이 제거되었으며, HTTP 클라이언트 API가 표준으로 도입

     

    Java 12,13,14,15(2019.03 ~ 2020.09)

    : 12,13,14,15 버전들에서는 주로 개발 생산성과 성능 개선에 초점을 맞추었습니다. 예를 들면, Switch Expressions, Compact Number Formatting, Text Blocks, Garbage Collector 개선 등이 도입

     

    Java 16(2021.03.16)

    : 이 버전에서는 패턴 매칭(Pattern Matching)과 메모리 관리 개선, Unix 도메인 소켓 채널(Unix Domain Socket Channels)등의 기능이 추가

     

    Java 17 LTS(2021.09.14)

    : 이 버전에서는 Sealed 클래스, 패턴 인스턴스화, 지역 변수를 포함해 확장한 switch 문, 힙 메모리 정리 기능의 개선 등이 도입

     

    2023.07 기준 오라클 공식홈페이지는 Java 20을 릴리스 하고 있다.

     

    LTS 지원하는 JDK 8 & JDK 11 & JDK 17 버전의 자세한 업데이트 내용은 여기어때 기술블로그에서 잘 설명되어있다. 여기를 확인

     

    GC(Garbage Collector)

    더 이상 참조되지 않는 메모리 객체를 모아 제거하는 역할을 수행

    일반적으로 자동으로 실행되지만, 수동으로 실행하기 위해 `System.gc()`를 사용할 수 있음(다만, 실행이 보장되지는 않음)

    다만, `System.gc()`는 성능의 막대한 저하를 일으킬 수 있어 실 사용은 하지 않는 편이다.

     

    앞으로 사용되지 않는 객체의 메모리를 Garbage 라고 부르고, 이런 Garbage 를 정해진 스케줄에 의해 정리해주는 것을 GC(Garbage Collection)라 부른다.

     

    Garbage Collection

    자바의 메모리 관리 기법으로 애플리케이션이 동적으로 할당했던 메모리 영역 중 더이상 사용하지 않는 영역을 정리하는 기능이다. GC(Garbage Collection)는 Heap 메모리에서 활동하며, JVM에서 GC의 스케줄링을 담당하며 개발자가 직접 관여하지 않아도 더 이상 사용하지 않는 점유된 메모리를 제거해주는 역할을 담당한다.

     

    GC 원리

    아래 가정을 기반으로 메모리 구조를 크게 2개로 물리적 공간을 나눈다 (Young Generation, Old Generation)

    • 대부분의 객체는 금방 접근 불가능(Unreachable)한 상태가 된다.
      • 대부분의 객체는 중괄호 `{}` 안에서 생성되고 이 객체들은 괄호가 끝나는 시점에서 더 이상 사용되지 않는다
      • 특수한 경우에는 오래 사용할 수 있지만, 대부분의 경우 unreachable 한 상태가 되어 GC의 대상이 된다.
    • 오래된 객체에서 젊은 객체로의 참조는 아주 적게 발생한다.
      • 일반적으로 순차적인 로직에 의해 객체를 생성하여 활용한다.
      • 이 과정에서 앞에 생성된 객체는 그 다음의 로직에서 사용된 이후 대부분 사용되지 않게된다.
      • 이런 특성으로 더 이상 참조되지 않는 객체에 대해 GC를 할 수 있다.

     

    public class Main {
        public static void main(String[] args) {
            int num1 = 10;
            int num2 = 5;
            int sum = num1 + num2;
            String name = "애런";
            
            System.out.println(sum);
            System.out.println(name);
        }
    }

     

     

     

    Heap Area

    GC는 간단하게 말해서 Heap Area 에서 더 이상 사용하지 않는 메모리를 제거하는 것을 의미한다.

    전통적인 Heap Area 는 아래와 같은 구조를 가지고 있고, Eden, Survivor1, Survivor2, Old Generation 으로 구분된다.

    Eden S0 S1 Old Generation Permanent

    Eden, S0, S1, Old Generation 을 Heap Area,

    Eden, S0, S1 을 Young Generation,

    Permanent 는 Java 7 버전까지 Heap Area 에 존재했고 Java 8 버전부터 Native Method Stack 에 편입

     

    GC Algorithm

    GC는 기본적으로 Garbage 대상을 식별하고 그 대상을 메모리에서 제거하는 것이다.

    이 기본 동작과 관련된 알고리즘은 아래와 같다.

    • Reference Counting Algorithm
    • Mark-and-Sweep Algorithm
      • Reference Counting Algorithm의 단점을 극복하기 위해 나온 알고리즘
    • Mark-and-Compact Algorithm
      • Mar-and-Sweep 알고리즘에서 발생하는 점유 메모리 분산(Fragmentation)을 해결하기 위해 나온 알고리즘
    • Copying Algorithm
    • Concurrent Mark-Sweep
    • Generational Algorithm

    현재는 위 알고리즘 중 사용되지 않는 것도 있다.

    각 GC Algorithm 의 장점과 단점 동작원리는 여유가 될 때 따로 포스팅을 해볼 계획이다.

     

    GC 종류

    • Serial GC
      : 하나의 CPU로 Young Generation 과 Old Generation 을 연속적으로 처리하는 방식
      가장 오래된 GC이며 Mark-and-Compact 알고리즘을 사용
      GC가 수행될 때 STW(Stop The World)가 발생함
    • Parallel GC
      : 자바 7~8버전에서 Default 로 설정되어 있는 GC 이고 Parallel GC의 목표는 다른 CPU가 GC의 진행시간 동안 대기 상태로 남아있는 것을 최소화 하는 것이다.
      GC 작업을 병렬로 처리하여 STW 시간이 비교적 짧다.
    • Parallel Compacting GC
      : Parallel GC에서 Old Generation 의 처리 알고리즘을 변경한다.
    • Concurrent Mark-Sweap(CMS) GC
      : Application 의 Thread 와 GC Thread 가 동시에 실행되어 STW를 최소화 하는 GC 이고 Parallel GC와 가장 큰 차이점은 Compaction 작업 유무로 구분된다.
      Compaction: 메모리 공간에서 사용하지 않는 빈 공간이 없도록 옮겨서 메모리 분산을 제거하는 작업
    • Garbage First(G1) GC
      : 지금까지 만들어진 GC는 고용량 & 고성능을 요구하는 애플리케이션에는 적합하지 않다라는 평가가 있었다.
      G1 GC 는 큰 메모리에서 사용하기 적합한 GC(대규모 Heap 사이즈에서 짧은 GC 시간을 보장하는데 목적을 둔다)
      전체 Heap 영역을 Region 이라는 영역으로 분할하여 상황에 따라 역할이 동적으로 부여된다.
    • Z GC
      : ZPage 라는 영역을 사용하며, G1 GC의 Region 은 크기가 고정인데 비해 Zpage는 2mb 배수로 동적으로 운영된다.
      정지 시간이 최대 10ms 를 초과하지 않는 것을 목적으로 운영되고 Heap 크기가 증가하더라도 정지 시간이 증가하지 않는 것이 특징이다. (레퍼런스가 적고 실험적으로 도입된 단계라서 많이 사용하지 않는다)

     

    Stop The World

    GC를 수행하기 위해 JVM이 멈추는 현상을 의미하고 GC가 작동하려는 동안 GC관련 Thread를 제외한 모든 Thread 는 멈춘다. 일반적으로 `튜닝`이라는 것은 이 시간을 최소화하는 것을 의미한다.

Designed by Tistory.