Alasan 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 nyata pada API, dan ada peningkatan yang meningkatkan penggunaan startup, performa, dan memori.

Transisi ke Java 11

Transisi ke Java 11 dapat dilakukan dengan cara stepwise. Tidak diperlukan kode untuk menggunakan modul Java untuk berjalan 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, loader kelas, dan refleksi yang tidak digunakan lagi.

Microsoft Java Engineering Group memiliki panduan untuk transisi dari Java 8 ke Java 11. Panduan Migrasi Java Platform, 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 yang lebih kecil dan memungkinkan aplikasi ditautkan secara statis, menggunakan jlink, ke dalam runtime kustom untuk penyebaran. 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 memulai. Teknik pengoptimalan yang digunakan oleh JVM untuk meningkatkan performa aplikasi dapat lebih efektif karena modul mengodekan komponen mana yang dibutuhkan kelas.

Untuk programmer, modul membantu memberlakukan enkapsulasi yang kuat dengan mengharuskan deklarasi eksplisit yang mengemas ekspor modul dan komponen mana yang diperlukannya, dan dengan membatasi akses reflektif. Tingkat enkapsulasi 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

Java Flight Recorder [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 sumber terbuka di Java 11.

Java Mission Control [6]

Java Mission Control (JMC) menyediakan tampilan grafis data yang dikumpulkan oleh Java Flight Recorder (JFR) dan 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, penyempitan 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 mengambil sampel alokasi heap Java. Pengambilan sampel memiliki overhead rendah dan dapat diaktifkan terus menerus. Sementara alokasi tumpukan dapat dipantau dengan Java Flight Recorder (JFR), metode pengambilan sampel di JFR hanya berfungsi pada alokasi. Implementasi JFR juga dapat melewatkan alokasi. Sebaliknya, pengambilan sampel timbunan di Java 11 dapat memberikan informasi tentang objek hidup dan 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]

Mendapatkan rekam jepret tumpukan untuk utas saat ini sering digunakan saat pengelogan. 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 dalam Java 9) memberikan rekam jepret tumpukan dan menyediakan metode yang memberikan kontrol terperinci kepada pemrogram tentang cara mengonsumsi jejak tumpukan.

Pengumpulan Sampah [10]

Pengumpul sampah berikut tersedia di Java 11: Serial, Parallel, Garbage-First, dan Epsilon. Pengumpul sampah default di Java 11 adalah Garbage First Garbage Collector (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. Kolektor Shenandoah adalah kolektor jeda rendah yang mengurangi waktu jeda GC dengan melakukan lebih banyak pengumpulan sampah secara bersamaan dengan program Java yang sedang berjalan. Shenandoah adalah fitur eksperimental di Java 12, tetapi ada backport ke Java 11. Kolektor Concurrent Mark and Sweep (CMS) tersedia tetapi tidak digunakan lagi sejak Java 9.

JVM menetapkan default GC untuk kasus penggunaan rata-rata. Sering kali, 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 koleksi lengkap, tetapi ketika koleksi bersamaan tidak dapat mengklaim kembali memori dengan cukup cepat, fallback penuh GC akan terjadi. 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 default ukuran heap maksimum ke ¼ dari memori fisik host yang mendasar. 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 heap maksimum default adalah ¼ 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.

Catatan

Sebagian besar pekerjaan pengaktifan cgroup didukung ke Java 8 pada jdk8u191. Perbaikan lebih lanjut mungkin belum tentu didukung ke 8.

File jar multi-rilis [13]

Dimungkinkan di Java 11 untuk membuat file jar yang berisi beberapa versi file kelas khusus rilis Java. File jar multi-rilis memungkinkan pengembang pustaka untuk mendukung beberapa versi Java tanpa harus mengirim beberapa versi file jar. Untuk konsumen pustaka ini, file jar multi-rilis memecahkan masalah harus mencocokkan file jar tertentu dengan target runtime tertentu.

Peningkatan performa lain-lain

Perubahan berikut pada JVM berdampak langsung pada performa.

  • JEP 197: Cache Kode Tersegmentasi [14] - Membagi cache kode menjadi segmen yang berbeda. Segmentasi ini memberikan kontrol yang lebih baik atas 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 jumlah ruang yang diperlukan untuk menyimpan String.

  • JEP 310: Berbagi Class-Data Aplikasi [16] - berbagi Class-Data mengurangi waktu mulai dengan memungkinkan kelas yang diarsipkan dipetakan memori pada waktu proses. Berbagi Class-Data Aplikasi memperluas berbagi data kelas dengan memungkinkan kelas aplikasi ditempatkan dalam arsip CDS. Ketika beberapa JVM berbagi file arsip yang sama, memori disimpan, dan waktu respons sistem secara keseluruhan meningkat.

  • JEP 312: Jabat Tangan Utas Lokal [17] - Memungkinkan untuk menjalankan panggilan balik pada utas tanpa melakukan titik aman VM global, yang membantu VM mencapai latensi yang lebih rendah dengan mengurangi jumlah titik aman global.

  • Alokasi Malas dari Utas Penyusun [18] - Dalam mode kompilasi bertingkat, VM memulai sejumlah besar utas penyusun. 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 penyusun dari setiap jenis selama 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: Handel Variabel [19] - Mendefinisikan sarana standar untuk memanggil 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: Petunjuk Spin-Wait [21] - Menyediakan API yang memungkinkan Java untuk mengisyaratkan sistem run-time bahwa ia berada dalam perulangan putaran. 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 menggantikan API HttpURLConnection warisan.

Referensi

[1] Oracle Corporation, "Catatan Rilis Java Development Kit 9," (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, "Proyek Jigsaw," 22 September 2017. (Online). Tersedia: http://openjdk.java.net/projects/jigsaw/. (Diakses 13 November 2019).

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

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

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

[8] Oracle Corporation, "JEP 331: Pembuatan Profil Timbunan Overhead Rendah," 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: Menjadikan 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: Pengumpul Sampah Tanpa Operasi," 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: Kode Cache Tersegmentasi," 28 April 2017. (Online). Tersedia: http://openjdk.java.net/jeps/197. (Diakses 13 November 2019).

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

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

[17] Oracle Corporation, "JEP 312: Jabat Tangan Utas Lokal," 21 Agustus 2019. (Online). Tersedia: https://openjdk.java.net/jeps/312. (Diakses 13 November 2019).

[18] Oracle Corporation, "JDK-8198756: Alokasi malas dari utas penyusun," 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: Handle Variabel," 17 Agustus 2017. (Online). Tersedia: https://openjdk.java.net/jeps/193. (Diakses 13 November 2019).

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

[21] Oracle Corporation, "JEP 285: Petunjuk Spin-Wait," 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).