하마
6k
2020-09-23 11:44:42 작성 2020-09-28 10:11:14 수정됨
10
5394

Java 11 로 전환해야 하는 이유


8버전의 람다,스트림, 9버전의 모듈이라는 커다란 변경 이후 11버전의 변경점에 대한 5분 정리.

빨강색 핵심만 보시면 됩니다.





Java 11로 전환해야 하는 이유  /  OpenJDK 11 version  정리

(추가: Spring5 Webflux로 시작/전환하는 조직들도 많아 졌으면...정말 좋은데..)  

API에 대한 눈에 띄는 추가 및 수정 사항이 있으며,
시작, 성능 및 메모리 사용을 개선하는 향상된 기능이 있습니다.그리고 LTS 버전입니다.

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

java 10버전에 편리한 var 구문이 생겨난 상황에서, 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 지원
// 비동기 호출 예
public class HttpClientAsynchronous {
private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.GET()
.uri(URI.create("https://httpbin.org/get"))
.setHeader("User-Agent", "Java 11 HttpClient Bot")
.build();
CompletableFuture<HttpResponse<String>> response =
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
String result = response.thenApply(HttpResponse::body).get(5, TimeUnit.SECONDS);
System.out.println(result);
}
} // 여러군데 비동기 호출
public class HttpClientCustomExecutor {
// custom executor
private static final ExecutorService executorService = Executors.newFixedThreadPool(5);
private static final HttpClient httpClient = HttpClient.newBuilder()
.executor(executorService)
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build(); public static void main(String[] args) throws Exception {
List<URI> targets = Arrays.asList(
new URI("https://httpbin.org/get?name=mkyong1"),
new URI("https://httpbin.org/get?name=mkyong2"),
new URI("https://httpbin.org/get?name=mkyong3"));

        List<CompletableFuture<String>> result = targets.stream()
.map(url -> httpClient.sendAsync(
HttpRequest.newBuilder(url)
.GET()
.setHeader("User-Agent", "Java 11 HttpClient Bot")
.build(),
HttpResponse.BodyHandlers.ofString())
.thenApply(response -> response.body()))
.collect(Collectors.toList()); for (CompletableFuture<String> future : result) {
System.out.println(future.get());
}
}
}
참고로 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. 가비지 수집 

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

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

엡실론 

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

Docker 컨테이너의 향상된 기능 

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

다중 릴리스 jar 파일 

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

6. 성능 향상

JVM 성능향상) 

  • JEP 197: Segmented Code Cache[14] - 코드 캐시를 고유 세그먼트로 나눕니다. 이러한 구분은 JVM 메모리 공간을 보다 효율적으로 제어하고, 컴파일된 메서드의 검색 시간을 단축하고, 코드 캐시의 조각화를 크게 줄이고, 성능을 향상시킵니다.

  • JEP 254: Compact Strings[15] - 문자 인코딩에 따라 문자열의 내부 표현을 문자당 2바이트에서 문자당 1~2바이트로 변경합니다. 대부분의 문자열은 ISO-8859-1/라틴어-1 문자를 포함하므로 이 변경 내용으로 인해 문자열을 저장하는 데 필요한 공간이 효율적으로 변경됩니다.

  • JEP 310: Application Class-Data Sharing[16] - 클래스-데이터 공유는 보관된 클래스가 런타임 시 메모리에 매핑될 수 있게 하여 시작 시간을 줄여줍니다. 애플리케이션 클래스-데이터 공유는 애플리케이션 클래스를 CDS 보관함에 배치할 수 있도록 하여 클래스-데이터 공유를 확장합니다. 여러 JVM이 동일한 보관 파일을 공유하는 경우 메모리가 저장되고 전체 시스템 응답 시간이 단축됩니다.

  • JEP 312: Thread-Local Handshakes[17] - 글로벌 VM 세이프포인트를 수행하지 않고 스레드에 대한 콜백을 실행하여 VM이 글로벌 세이프포인트의 수를 줄여 대기 시간을 단축할 수 있게 해줍니다.

  • Lazy Allocation of Compiler Threads[18] - VM은 단계별 컴파일 모드에서 다량의 컴파일러 스레드를 시작합니다. 이 모드는 CPU가 여러 개 있는 시스템에서 기본값입니다. 이러한 스레드는 사용 가능한 메모리 또는 컴파일 요청 수에 관계없이 생성됩니다. 스레드는 유휴 상태일 때(거의 모든 시간) 메모리를 사용하므로 리소스를 비효율적으로 사용합니다. 이 문제를 해결하기 위해 시작 시 각 유형의 컴파일러 스레드를 하나씩만 시작하도록 구현이 변경되었습니다. 추가 스레드를 시작하고 사용하지 않는 스레드를 종료하는 것은 동적으로 처리됩니다.

핵심 라이브러리 성능 향상) 

  • JEP 193: Variable Handles[19] - 표준을 정의한다는 것은 개체 필드 및 배열 요소, 메모리 정렬의 세부적인 제어를 위한 표준 펜스 작업 세트, 참조된 개체의 강력한 연결성을 유지하기 위한 표준 연결성 펜스 작업에 대한 다양한 java.util.concurrent.atomic 및 sun.misc.Unsafe 작업의 동급 요소를 호출하는 것을 의미합니다.

  • JEP 269: Convenience Factory Methods for Collections[20] - 소량의 요소를 사용하여 컬렉션 및 맵 인스턴스를 편리하게 만들 수 있게 해주는 라이브러리 API를 정의합니다. 컬렉션 인터페이스에서 간결하고 수정할 수 없는 컬렉션 인스턴스를 만드는 고정 팩터리 메서드입니다. 이러한 인스턴스는 본질적으로 더 효율적입니다. API는 조밀하게 표시되고 래퍼 클래스가 없는 컬렉션을 만듭니다.

  • JEP 285: Spin-Wait Hints[21] - Java에서 스핀 루프에 있음을 런타임 시스템에 암시할 수 있게 해주는 API를 제공합니다. 특정 하드웨어 플랫폼은 스레드가 바쁜 대기(busy-wait) 상태라고 소프트웨어가 알려주면 이점을 얻을 수 있습니다.

  • JEP 321: HTTP Client(Standard) [22]- HTTP/2 및 WebSocket을 구현하고 레거시 HttpURLConnection API를 대체할 수 있는 새로운 HTTP 클라이언트 API를 제공합니다.




    P.S

    다시 자바를 하면서 느낀게  "자바는 꾸준히 발전하고 있는 재밌고 가치있는 중심 언어이다"  입니다.

    26
    15
    • 댓글 10

    • 커피랑
      145
      2020-09-23 14:03:01

      감사합니다. 핵심을 자세하게 정리해주셔서 보기 편했습니다.

      java 8 이후부터는 업데이트내역을 잘 확인하지 못했는데.. 이번 기회에 변경된 점들을 알아봐야겠네요.

    • zepinos
      20k
      2020-09-23 16:32:12

      전환을 하기 쉽지 않은 허들이 있는게 보급이 늦어지는 이유라 생각합니다. 직소 프로젝트 때문에 수많은 라이브러리들과 기존 코드에 수정이 불가피해졌고, 아직 코틀린의 UI 라이브러리 같이 8 까지만 지원하는게 꽤나 있어서요.

      11로 무난하게 넘어올 수 있다면 15 이후도 쉽게 넘어갈 꺼라 생각됩니다.

    • 빠다
      501
      2020-09-24 07:16:08
      정리 감사합니다.
    • 칠역한천겁
      2k
      2020-09-24 10:47:10

      오오..잘 읽었습니다. ^^

    • codeShooter
      24
      2020-09-24 16:20:22
      와우 감사합니다 !
    • kiss
      533
      2020-09-25 13:18:53

      좋은글 감사합니다. 하마님

      다만 4번 이후부턴 정신줄놓고 봤네요. 이해가 잘안되서.. ㅜ.ㅜ

      이넘의 공부는 끝이없네요. ㅋ

    • kim
      336
      2020-09-25 19:50:12

      요즘은 괜찮은가 모르겠는데 예전에 JDK 11 설치하면 호환성 이슈로 안드로이드 개발을 못하는 문제가 있었습니다.

      여기 개발자들 HTML도 치고 스프링도 치고 안드로이드 앱개발도 하고.. 부장님이 시키면 다 해야 하잖아요 ㅠㅠ

    • 쓸모있는 개발
      119
      2020-09-26 14:16:11

      kim

      안드로이드 스튜디오는 jdk 11안되더라고요

      안드로이드 스튜디오설치시 내장되는 jdk 설정하면되네요

    • 길록
      69
      2020-10-07 07:59:08
      깔끔하고 핵심적으로 정리 잘해주셔서 감사드립니다!

      저한테는 숨이 턱막히게되는 내용들의 연속이네요..ㅠ..

      자바 11쓰다가 기업에서 자바 8을 많이 사용하니
      자바 8로 빽 해야하나 두 버전이 무슨 차이들이 있는지는
      생각해본적도 없고 아무생각없이 쓰고있었는데

      다시 자주 자주 들어와서 찬찬히 살펴보고 더 발전하겠습니다!
    • 루네디아
      41
      2020-10-12 16:29:49 작성 2020-10-12 16:30:06 수정됨

      11이후 LTS가 빨리나와서 다중 텍스트 블록을 사용하고싶네요..

    • 로그인을 하시면 댓글 을 등록할 수 있습니다.