Alasan untuk pindah ke Java 11 dan seterusnya

Pertanyaannya bukan jika Anda harus pindah ke Java 11 atau versi yang lebih baru, tetapi kapan. Dalam beberapa tahun ke depan, Java 8 tidak akan lagi didukung, dan pengguna harus pindah ke Java 11 atau yang lebih baru. Kami berpendapat bahwa ada manfaat untuk pindah ke Java 11 dan mendorong tim untuk melakukannya sesegera mungkin.

Sejak Java 8, fitur baru telah ditambahkan dan penyempurnaan telah dibuat. Ada penambahan dan modifikasi yang terlihat pada API, dan ada peningkatan yang meningkatkan startup, performa, dan penggunaan memori.

Transisi ke Java 11

Transisi ke Java 11 dapat dilakukan secara bertahap. Tidak diwajibkan bagi kode untuk menggunakan modul Java saat dijalankan pada Java 11. Java 11 dapat digunakan untuk menjalankan kode yang dikembangkan dan dibangun dengan JDK 8. Tetapi ada beberapa masalah potensial, terutama mengenai API yang tidak digunakan lagi, loader kelas, dan refleksi.

Microsoft Java Engineering Group memiliki panduan untuk transisi dari Java 8 ke Java 11. Platform Java, Panduan Migrasi Oracle JDK 9 Edisi Standar dan Status Sistem Modul: Kompatibilitas dan Migrasi adalah panduan berguna lainnya.

Perubahan tingkat tinggi antara Java 8 dan 11

Bagian ini tidak menghitung semua perubahan yang dibuat dalam Java versi 9 [1], 10 [2], dan 11 [3]. Perubahan yang berdampak pada performa, diagnostik, dan produktivitas disorot.

Modul [4]

Modul mengatasi masalah konfigurasi dan enkapulasi yang sulit dikelola dalam aplikasi skala besar yang berjalan di classpath. Modul adalah koleksi kelas dan antarmuka Java yang menjelaskan sendiri, serta sumber daya terkait.

Modul memungkinkan untuk menyesuaikan konfigurasi runtime yang hanya berisi komponen yang diperlukan oleh aplikasi. Penyesuaian ini membuat jejak memori yang lebih kecil dan memungkinkan aplikasi untuk ditautkan secara statis, menggunakan jlink, ke dalam runtime kustom agar dapat di-deploy. Jejak yang lebih kecil ini dapat sangat berguna dalam arsitektur layanan mikro.

Secara internal, JVM dapat memanfaatkan modul dengan cara yang membuat pemuatan kelas lebih efisien. Hasilnya adalah runtime yang lebih kecil, lebih ringan, dan lebih cepat untuk dijalankan. Teknik pengoptimalan yang digunakan oleh JVM untuk meningkatkan performa aplikasi bisa lebih efektif karena modul mengodekan komponen mana yang diperlukan kelas.

Untuk programmer, modul membantu memberlakukan enkapsulasi yang kuat dengan memerlukan deklarasi eksplisit mengenai paket mana yang diekspor oleh modul dan komponen mana yang diperlukan, serta dengan membatasi akses refleksi. Tingkat enkapulasi ini membuat aplikasi lebih aman dan lebih mudah dipertahankan.

Aplikasi dapat terus menggunakan classpath dan tidak harus beralih ke modul sebagai persyaratan untuk berjalan di Java 11.

Pembuatan profil dan diagnostik

Perekam Penerbangan Java [5]

Java Flight Recorder (JFR) mengumpulkan data diagnostik dan pembuatan profil dari aplikasi Java yang sedang berjalan. JFR memiliki sedikit dampak pada aplikasi Java yang sedang berjalan. Data yang dikumpulkan kemudian dapat dianalisis dengan Java Mission Control (JMC) dan alat lainnya. Sedangkan JFR dan JMC adalah fitur komersial di Java 8, keduanya adalah open source di Java 11.

Java Mission Control [6]

Java Mission Control (JMC) menyediakan tampilan grafis data yang dikumpulkan oleh Java Flight Recorder (JFR) dan merupakan sumber terbuka di Java 11. Selain informasi umum tentang aplikasi yang sedang berjalan, JMC memungkinkan pengguna untuk menelusuri paling detail data. JFR dan JMC dapat digunakan untuk mendiagnosis masalah runtime seperti kebocoran memori, overhead GC, metode panas, hambatan utas, dan memblokir I/O.

Pengelogan terpadu [7]

Java 11 memiliki sistem pengelogan umum untuk semua komponen JVM. Sistem pengelogan terpadu ini memungkinkan pengguna untuk menentukan komponen apa yang akan dicatat, dan ke tingkat apa. Pengelogan berbutir halus ini berguna untuk melakukan analisis akar penyebab pada crash JVM dan untuk mendiagnosis masalah performa di lingkungan produksi.

Pembuatan profil timbunan overhead rendah [8]

API baru telah ditambahkan ke Java Virtual Machine Tool Interface (JVMTI) untuk menyampel alokasi heap Java. Pengambilan sampel memiliki overhead rendah dan dapat diaktifkan terus menerus. Meskipun alokasi timbunan dapat dipantau dengan Java Flight Recorder (JFR), metode pengambilan sampel dalam JFR hanya berfungsi pada alokasi. Implementasi JFR juga dapat terlewat alokasi. Sebaliknya, pengambilan sampel heap di Java 11 dapat memberikan informasi tentang objek yang hidup dan yang sudah mati.

Vendor Pemantauan Performa Aplikasi (APM) mulai menggunakan fitur baru ini dan Java Engineering Group sedang menyelidiki potensi penggunaannya dengan alat pemantauan performa Azure.

StackWalker [9]

Pengambilan cuplikan tumpukan memori untuk utas saat ini sering digunakan dalam pencatatan log. Masalahnya adalah berapa banyak jejak tumpukan yang akan dicatat, dan apakah akan mencatat jejak tumpukan sama sekali. Misalnya, seseorang mungkin ingin melihat jejak tumpukan hanya untuk pengecualian tertentu dari metode . Kelas StackWalker (ditambahkan di Java 9) memberikan rekam jepret tumpukan dan menyediakan metode yang memberikan kontrol terperinci kepada pemrogram tentang cara menggunakan jejak tumpukan.

Pengumpulan sampah [10]

Pengumpul sampah berikut tersedia di Java 11: Serial, Paralel, Garbage-First, dan Epsilon. Pengumpul sampah default di Java 11 adalah Pengumpul Sampah Sampah Pertama (G1GC).

Tiga kolektor lain disebutkan di sini untuk kelengkapan. Z Garbage Collector (ZGC) adalah kolektor latensi rendah bersamaan yang mencoba untuk menjaga waktu jeda di bawah 10ms. ZGC tersedia sebagai fitur eksperimental di Java 11. Pengumpul Shenandoah adalah kolektor jeda rendah yang mengurangi waktu jeda GC dengan melakukan lebih banyak pengumpulan sampah bersamaan dengan program Java yang sedang berjalan. Shenandoah adalah fitur eksperimental di Java 12, tetapi ada backport ke Java 11. Kolektor Mark dan Sapu Bersamaan (CMS) tersedia tetapi tidak digunakan lagi sejak Java 9.

JVM menetapkan default GC untuk kasus penggunaan rata-rata. Seringkali, default ini, dan pengaturan GC lainnya, perlu disetel untuk throughput atau latensi optimal, sesuai dengan persyaratan aplikasi. Menyetel GC dengan benar membutuhkan pengetahuan mendalam tentang GC, keahlian yang disediakan Microsoft Java Engineering Group .

G1GC

Pengumpul sampah default di Java 11 adalah pengumpul sampah G1 (G1GC). Tujuan G1GC adalah untuk mencapai keseimbangan antara latensi dan throughput. Pengumpul sampah G1 mencoba mencapai throughput tinggi dengan memenuhi tujuan waktu jeda dengan probabilitas tinggi. G1GC dirancang untuk menghindari pengumpulan penuh, tetapi ketika pengumpulan bersamaan tidak dapat mengklaim kembali memori dengan kecepatan yang cukup, GC penuh fallback akan dilakukan. GC lengkap menggunakan jumlah utas pekerja paralel yang sama dengan koleksi muda dan campuran.

GC Paralel

Kolektor paralel adalah pengumpul default di Java 8. Parallel GC adalah pengumpul throughput yang menggunakan beberapa utas untuk mempercepat pengumpulan sampah.

Epsilon [11]

Pengumpul sampah Epsilon menangani alokasi tetapi tidak mengklaim kembali memori apa pun. Ketika tumpukan habis, JVM akan dimatikan. Epsilon berguna untuk layanan berumur pendek dan untuk aplikasi yang dikenal bebas sampah.

Peningkatan untuk kontainer docker [12]

Sebelum Java 10, batasan memori dan CPU yang ditetapkan pada kontainer tidak dikenali oleh JVM. Di Java 8, misalnya, JVM akan menetapkan secara default ukuran heap maksimum menjadi ΒΌ dari memori fisik host yang mendasarinya. Dimulai dengan Java 10, JVM menggunakan batasan yang diatur oleh grup kontrol kontainer (cgroup) untuk mengatur batas memori dan CPU (lihat catatan di bawah). Misalnya, ukuran timbunan maksimum default adalah 1/4 dari batas memori kontainer (misalnya, 500MB untuk -m2G).

Opsi JVM juga ditambahkan untuk memberi pengguna kontainer Docker kontrol halus atas jumlah memori sistem yang akan digunakan untuk tumpukan Java.

Dukungan ini diaktifkan secara default dan hanya tersedia di platform berbasis Linux.

Nota

Sebagian besar aktivasi cgroup di-backport ke Java 8 pada jdk8u191. Perbaikan lebih lanjut mungkin tidak akan diterapkan ke versi 8.

File jar multi-rilis [13]

Dimungkinkan di Java 11 untuk membuat file jar yang berisi beberapa versi file kelas khusus rilis Java. Berkas jar multi-rilis memungkinkan pengembang pustaka untuk mendukung berbagai versi Java tanpa harus mendistribusikan banyak versi berkas jar. Bagi pengguna pustaka perangkat lunak ini, file jar multi-rilis memecahkan masalah keharusan mencocokkan file jar tertentu dengan target runtime tertentu.

Peningkatan performa lain-lain

Perubahan berikut pada JVM berdampak langsung pada performa.

  • JEP 197: Segmented Code Cache [14] - Membagi cache kode menjadi segmen yang berbeda. Segmentasi ini memberikan kontrol yang lebih baik terhadap jejak memori JVM, mempersingkat waktu pemindaian metode yang dikompilasi, secara signifikan mengurangi fragmentasi cache kode, dan meningkatkan performa.

  • JEP 254: Compact Strings [15] - Mengubah representasi internal String dari dua byte per karakter menjadi satu atau dua byte per karakter, tergantung pada pengodean karakter. Karena sebagian besar String berisi karakter ISO-8859-1/Latin-1, perubahan ini secara efektif mengurangi setengah dari jumlah ruang yang diperlukan untuk menyimpan String.

  • JEP 310: Berbagi Kelas-Data Aplikasi [16] - Berbagi Kelas-Data mengurangi waktu awal dengan memungkinkan kelas yang diarsipkan dipetakan ke memori saat runtime. Berbagi Data Kelas Aplikasi memperluas berbagi data kelas dengan memungkinkan kelas aplikasi untuk ditempatkan di arsip CDS. Ketika beberapa JVM berbagi file arsip yang sama, memori disimpan, dan waktu respons sistem keseluruhan meningkat.

  • JEP 312: Thread-Local Handshakes [17] - Memungkinkan pelaksanaan callback pada utas tanpa melakukan titik aman global VM, yang membantu VM mencapai latensi yang lebih rendah dengan mengurangi jumlah titik aman global.

  • Lazy Allocation of Compiler Threads [18] - Dalam mode kompilasi berjenjang, VM memulai sejumlah besar utas kompilator. Mode ini adalah default pada sistem dengan banyak CPU. Utas ini dibuat terlepas dari memori yang tersedia atau jumlah permintaan kompilasi. Utas mengonsumsi memori bahkan ketika diam (yang hampir sepanjang waktu), yang menyebabkan penggunaan sumber daya yang tidak efisien. Untuk mengatasi masalah ini, implementasi telah diubah untuk memulai hanya satu utas kompilator dari setiap jenis selama proses startup. Memulai utas tambahan, dan mematikan utas yang tidak digunakan, ditangani secara dinamis.

Perubahan berikut pada pustaka inti berdampak pada performa kode baru atau yang dimodifikasi.

  • JEP 193: Variable Handles [19] - Mendefinisikan cara standar untuk memanggil setara berbagai operasi java.util.concurrent.atomic dan sun.misc.Unsafe pada bidang objek dan elemen array, serangkaian operasi pagar standar untuk kontrol urutan memori yang halus, dan operasi pagar keterjangkauan standar untuk memastikan bahwa objek yang direferensikan tetap sangat dapat dijangkau.

  • JEP 269: Metode Pabrik Kenyamanan untuk Koleksi [20] - Mendefinisikan API pustaka untuk membuatnya nyaman untuk membuat instans koleksi dan peta dengan sejumlah kecil elemen. Metode pabrik statis pada antarmuka koleksi yang membuat instans koleksi yang ringkas dan tidak dapat dimodifikasi. Instans ini secara inheren lebih efisien. API membuat koleksi yang diwakili secara ringkas dan tidak memiliki kelas pembungkus.

  • JEP 285: Spin-Wait Hints [21] - Menyediakan API yang memungkinkan Java memberikan petunjuk kepada sistem run-time bahwa ia berada dalam perulangan spin. Platform perangkat keras tertentu mendapat manfaat dari indikasi perangkat lunak bahwa utas dalam keadaan sibuk menunggu.

  • JEP 321: Klien HTTP (Standar) [22]- Menyediakan API klien HTTP baru yang mengimplementasikan HTTP/2 dan WebSocket dan dapat mengganti api HttpURLConnection warisan.

Referensi

[1] Oracle Corporation, "Java Development Kit 9 Release Notes," (Online). Tersedia: https://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html. (Diakses 13 November 2019).

[2] Oracle Corporation, "Catatan Rilis Java Development Kit 10," (Online). Tersedia: https://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html. (Diakses 13 November 2019).

[3] Oracle Corporation, "Catatan Rilis Java Development Kit 11," (Online). Tersedia: https://www.oracle.com/technetwork/java/javase/11u-relnotes-5093844.html. (Diakses 13 November 2019).

[4] Oracle Corporation, "Project Jigsaw," 22 September 2017. (Online). Tersedia: http://openjdk.java.net/projects/jigsaw/. (Diakses 13 November 2019).

[5] Oracle Corporation, "JEP 328: Flight Recorder," 9 September 2018. (Online). Tersedia: http://openjdk.java.net/jeps/328. (Diakses 13 November 2019).

[6] Oracle Corporation, "Mission Control," 25 April 2019. (Online). Tersedia: https://wiki.openjdk.java.net/display/jmc/Main. (Diakses 13 November 2019).

[7] Oracle Corporation, "JEP 158: Unified JVM Logging," 14 Februari 2019. (Online). Tersedia: http://openjdk.java.net/jeps/158. (Diakses 13 November 2019).

[8] Oracle Corporation, "JEP 331: Low-Overhead Heap Profiling," 5 September 2018. (Online). Tersedia: http://openjdk.java.net/jeps/331. (Diakses 13 November 2019).

[9] Oracle Corporation, "JEP 259: Stack-Walking API," 18 Juli 2017. (Online). Tersedia: http://openjdk.java.net/jeps/259. (Diakses 13 November 2019).

[10] Oracle Corporation, "JEP 248: Jadikan G1 sebagai Pengumpul Sampah Default," 12 September 2017. (Online). Tersedia: http://openjdk.java.net/jeps/248. (Diakses 13 November 2019).

[11] Oracle Corporation, "JEP 318: Epsilon: A No-Op Garbage Collector," 24 September 2018. (Online). Tersedia: http://openjdk.java.net/jeps/318. (Diakses 13 November 2019).

[12] Oracle Corporation, "JDK-8146115: Meningkatkan deteksi kontainer docker dan penggunaan konfigurasi sumber daya," 16 September 2019. (Online). Tersedia: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115. (Diakses 13 November 2019).

[13] Oracle Corporation, "JEP 238: File JAR Multi-Rilis," 22 Juni 2017. (Online). Tersedia: http://openjdk.java.net/jeps/238. (Diakses 13 November 2019).

[14] Oracle Corporation, "JEP 197: Cache Kode yang Tersegmentasi," 28 April 2017. (Online). Tersedia: http://openjdk.java.net/jeps/197. (Diakses 13 November 2019).

[15] Oracle Corporation, "JEP 254: Compact Strings," 18 Mei 2019. (Online). Tersedia: http://openjdk.java.net/jeps/254. (Diakses 13 November 2019).

[16] Oracle Corporation, "JEP 310: Application Class-Data Sharing," 17 Agustus 2018. (Online). Tersedia: https://openjdk.java.net/jeps/310. (Diakses 13 November 2019).

[17] Oracle Corporation, "JEP 312: Thread-Local Handshakes," 21/08/2019. (Online). Tersedia: https://openjdk.java.net/jeps/312. (Diakses 13 November 2019).

[18] Oracle Corporation, "JDK-8198756: Alokasi lambat untuk thread kompilator," 29 Okt 2018. (Online). Tersedia: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8198756. (Diakses 13 November 2019).

[19] Oracle Corporation, "JEP 193: Variable Handles," 17 Agustus 2017. (Online). Tersedia: https://openjdk.java.net/jeps/193. (Diakses 13 November 2019).

[20] Oracle Corporation, "JEP 269: Metode Factory yang Mudah untuk Koleksi," 26 Juni 2017. (Online). Tersedia: https://openjdk.java.net/jeps/269. (Diakses 13 November 2019).

[21] Oracle Corporation, "JEP 285: Spin-Wait Hints," 20 Agustus 2017. (Online). Tersedia: https://openjdk.java.net/jeps/285. (Diakses 13 November 2019).

[22] Oracle Corporation, "JEP 321: Klien HTTP (Standar)," 27 September 2018. (Online). Tersedia: https://openjdk.java.net/jeps/321. (Diakses 13 November 2019).