Java 11을 사용하는 이유


Java 8에서는 기존 버전들과 비교해서 가장 큰 변화가 있었다. 간략하게 정리하면 다음과 같다.

Java 8을 공부하고 써오다가 Java 11로 변환한 이유를 정리해보려고 한다.


1. 람다 파라미터를 위한 지역변수 표현

Java 10에서 var 구문이 생겼다.
Java 11에서는 람다 파라미터에서 좀 더 명시적으로 var를 사용할 수 있게 되었다.

list.stream()
    .map((@NotNull var s) -> s.toLowerCase())
    .collect(Collectors.toList());



2. HTTP Client (Standard)

Non-Blocking request and response 지원 (with CompletableFuture)
Backpressure 지원(java.util.concurrent.Flow 패키지를 통해 Rx Flow를 구현체에 적용)
Factory method 형태로 지원
HTTP/2 지원

spring5에서는 Rest Client에 RestTemplate 대신해 WebClient를 사용하여 비동기 구현을 할 수 있다.
기존 멀티스레드 방식을 버리고 Reactor(WebFlux)와 함께 스프링 기반 웹서비스를 구현할 경우,
그에 따른 성능과 효율 향상은 어마어마하다.


3. 모듈

모듈을 통해 애플리케이션에 필요한 구성 요소만 포함하는 런타임 구성을 사용자 지정할 수 있다.
이 사용자 지정은 메모리 공간을 더 적게 사용하며 애플리케이션이 jlink를 사용하여
배포용 사용자 지정 런타임에 정적으로 연결될 수 있게 해준다.
메모리 공간을 적게 사용하면 특히 마이크로서비스 아키텍처에서 유용할 수 있다.

내부적으로 JVM은 모듈을 활용하여 클래스 로딩을 보다 효율적으로 만들 수 있다.
그 결과 런타임이 더 작아지고, 더 가벼워져서 더 빠르게 시작할 수 있습니다.
모듈은 클래스에 필요한 구성 요소를 인코딩하기 때문에
JVM에서 애플리케이션 성능을 개선하기 위해 사용하는
최적화 기법의 효과가 더 좋아질 수 있다.

프로그래머의 경우 모듈은 모듈이 내보내는 패키지와 필요한 구성 요소를 명시적으로 선언하고
반사적 액세스를 제한하여 강력한 캡슐화를 적용하는 데 도움이 된다.
이 캡슐화 수준을 사용하면 애플리케이션을 더 안전하고 쉽게 유지 관리할 수 있다.



4. 프로파일링 및 진단

Java Flight Recorder

JFR(Java Flight Recorder)은 실행 중인 Java 애플리케이션에서 진단 및 프로파일링 데이터를 수집한다.
JFR 및 JMC는 Java 8에서 상용 기능이지만 Java 11에서는 둘 다 오픈 소스이다.


Java Mission Control

JMC(Java Mission Control)는 JFR(Java Flight Recorder)에서
수집한 데이터를 그래픽으로 표시하고 Java에서는 오픈 소스로 제공된다.
JFR 및 JMC를 사용하면 메모리 누수, GC 오버헤드, 핫 메서드,
스레드 병목 상태 및 I/O 블로킹과 같은 런타임 문제를 진단할 수 있다.


통합 로깅

Java 11에는 JVM의 모든 구성 요소에 대한 일반적인 로깅 시스템이 있다.
이 세분화된 로깅은 JVM 충돌에 대한 근본 원인 분석을 수행하고
프로덕션 환경에서 성능 문제를 진단하는 데 유용하다.


오버헤드가 낮은 힙 프로파일링

Java 힙 할당을 샘플링하는 데 사용할 수 있는 새 API가
JVMTI(Java Virtual Machine Tool Interface)에 추가되었다.
JFR 구현에서는 할당이 누락될 수도 있다.
반면 Java 11의 힙 샘플링은 라이브 개체와 데드 개체 모두에 대한 정보를 제공할 수 있다.
APM(애플리케이션 성능 모니터링) 공급업체가 이 새로운 기능을 활용하기 시작했다.


StackWalker

현재 스레드의 스택에 대한 스냅샷 가져오기는 로깅할 때 주로 사용된다.



5. Garbage 수집

Java 11에서 사용할 수 있는 가비지 수집기는 직렬, 병렬, 가비지 우선 및 엡실론(Epsilon)이다.
Java 11의 기본 가비지 수집기는 G1GC(가비지 우선 가비지 수집기)이다.

ZGC는 일시 중지 시간을 10ms 미만으로 유지하려고 하는 대기 시간이 짧은 동시 수집기이다.
ZGC는 Java 11에서 실험적 기능으로 사용할 수 있다.
CMS(Concurrent Mark and Sweep) 수집기는 사용할 수 있지만 Java 9 이후에는 사용되지 않는다.


Epsilon(엡실론)

엡실론 가비지 수집기는 할당을 처리하지만 메모리를 회수하지는 않는다.
힙이 소진되면 JVM이 종료된다.
엡실론은 수명이 짧은 서비스와 가비지를 사용하지 않는 것으로 알려진 애플리케이션에 유용하다.


Docker 컨테이너의 향상된 기능

Java 10 이전에 컨테이너에 설정된 메모리 및 CPU 제약 조건은 JVM에서 인식되지 않았다.
예를 들어 Java 8에서 JVM은 최대 힙 크기의 기본값을 기본 호스트의 실제 메모리의 ¼로 설정한다.
Java 10부터 JVM은 컨테이너 제어 그룹(cgroup)에 의해 설정된 제약 조건을 사용하여 메모리 및 CPU 제한을 설정한다.
예를 들어 기본 최대 힙 크기는 컨테이너의 메모리 제한의 ¼이다. (예: -m2G의 경우 500MB)


다중 릴리스 jar 파일

Java 11에서 클래스 파일의 여러 Java 릴리스별 버전을 포함하는 jar 파일을 만들 수 있다.



6. 성능 향상

JVM 성능 향상


핵심 라이브러리 성능 향상



7. Nest-Based Access Control

class Test {  
    static class Nest1 {  
        private int nest1Var; 
     } 
     static class Nest2 {  
        private int nest2Var;  
    }
}

위 코드와 같이 Nested class의 경우, Test, Nest1, Nest2는 모두 nestmate이다.
기존 JVM 상에서는 nestmate끼리 private 멤버 변수를 접근하려면 컴파일러가 중간에 bridge method를 만들어야 했다.
따라서, reflection을 사용하여 nestmate class의 private 멤버 변수에 접근하려고 하면,
llegalAccessException이 발생한다.

이러한 모순을 해결하고자, 새로운 ‘nest’라는 class file 개념을 도입해 하나의 중첩 클래스이지만
서로 다른 클래스파일로 분리하여 bridge method의 도움 없이도 서로의 private 멤버에 접근할 수 있도록 하였다.



참고