Java 11 ve ötesine geçme nedenleri
Asıl soru Java 11 veya sonraki bir sürüme geçmeniz gerekip gerekmediği değil ne zaman olduğudur. Önümüzdeki birkaç yıl içinde Java 8 artık desteklenmeyecektir ve kullanıcıların Java 11 veya sonraki bir sürüme geçmesi gerekecektir. Java 11’e geçmenin avantajlarını açıklıyor ve ekipleri bu geçişi mümkün olan en kısa zamanda yapmaya teşvik ediyoruz.
Java 8’den bu yana yeni özellikler eklenmiş ve geliştirmeler yapılmıştır. API’de dikkat çekici eklemeler ve değişiklikler, ayrıca kurulum, performans ve bellek kullanımını geliştiren iyileştirmeler vardır.
Java 11’e geçiş
Java 11’e geçiş işlemi adım adım gerçekleştirilebilir. Kodun Java 11 üzerinde çalıştırılması için Java modüllerini kullanması gerekmez. Java 11, JDK 8 ile geliştirilmiş ve oluşturulmuş kodu çalıştırmak için kullanılabilir. Ama öncelikle kullanım dışı bırakılmış API, sınıf yükleyicileri ve yansımayla ilgili bazı olası sorunlar vardır.
Microsoft Java Mühendislik Grubu, Java 8'den Java 11'e geçiş için bir kılavuza sahiptir. Oracle JDK 9 Geçiş Kılavuzu veModül Sisteminin Durumu: Uyumluluk ve Geçiş Standard Sürümü Java Platformu diğer yararlı kılavuzlardır.
Java 8 ile 11 arasındaki üst düzey değişiklikler
Bu bölüm Java sürüm 9 [1], 10 [2] ve 11 [3] sürümlerinde yapılan tüm değişiklikleri listelemez. Performansı, tanılamayı ve üretkenliği etkileyen değişiklikler vurgulanmıştır.
Modüller [4]
Modüller, sınıf yolu üzerinde çalıştırılan büyük ölçekli uygulamalarda zor yönetilen yapılandırma ve kapsülleme sorunlarına çözüm getiri. Modül kendi kendini açıklayan Java sınıfları, arabirimleri ve ilgili kaynaklar koleksiyonudur.
Modüller yalnızca uygulama tarafından gereken bileşenlerin yer aldığı çalışma zamanı yapılandırmalarını özelleştirmeyi mümkün kılar. Bu özelleştirme daha küçük bir ayak izi oluşturur ve dağıtım için uygulamanın jlink kullanılarak özel çalışma zamanına statik olarak bağlanmasını sağlar. Mikro hizmet mimarisinde bu küçük ayak izi özellikle yararlı olabilir.
Dahili olarak, JVM sınıf yüklemesini daha verimli hale getirecek bir yolla modüllerden yararlanabilir. Sonuçta daha küçük, daha basit ve daha hızlı başlatılan bir çalışma zamanı elde edilir. JVM tarafından uygulama performansını geliştirmek için kullanılan iyileştirme teknikleri daha etkili olabilir çünkü modüller bir sınıfa hangi bileşenlerin gerektiğini kodlar.
Programcılar açısından, modüller bir modülün dışarı aktardığı paketlerin ve bunun için gereken bileşenlerin açıkça bildirilmesini gerektirdiğinden ve yansımalı erişimi kısıtladığından güçlü bir kapsüllemeyi zorunlu tutmaya yardımcı olur. Bu kapsülleme düzeyi bir uygulamayı daha güvenli yapar ve bakımını kolaylaştırır.
Uygulama sınıf yolunu kullanmaya devam edebilir ve Java 11 üzerinde çalıştırılması için modüllere geçirilmesi gerekmez.
Profil oluşturma ve tanılama
Java Flight Recorder [5]
Java Uçuş Kaydedicisi (JFR) çalışan Java uygulamasından tanılama ve profil oluşturma verileri toplar. JFR’nin çalışan Java uygulaması üzerinde çok az etkisi vardır. Toplanan veriler Java Görev Kontrolü (JMC) ve diğer araçlarla analiz edilebilir. JFR ve JMC Java 8’de ticari özellikler olsa da Java 11’de her ikisi de açık kaynaktır.
Java Mission Control [6]
Java Mission Control (JMC), Java Flight Recorder (JFR) tarafından toplanan verilerin grafik görüntüsünü sağlar ve Java 11'de açık kaynak. Çalışan uygulama hakkında genel bilgilere ek olarak JMC, kullanıcının verilerde detaya gitmesine de olanak tanır. JFR ve JMC bellek sızıntıları, GC yükü, hareketli yöntemler, iş parçacığı performans sorunları ve engelleyici G/Ç gibi çalışma zamanı sorunlarını tanılamak için kullanılabilir.
Birleşik günlük [7]
Java 11’in tüm JVM bileşenleri için ortak bir günlük sistemi vardır. Bu birleşik günlük sistemi kullanıcının hangi bileşenlerin ne düzeyde günlüğe kaydedileceğini tanımlamasını sağlar. Bu ayrıntılı günlük JVM kilitlenmelerinde kök neden analizi gerçekleştirmek ve üretim ortamında performans sorunlarını tanılamak için yararlıdır.
Düşük ek yük yığın profili oluşturma [8]
Java yığın ayırmalarını örneklemek için Java Sanal Makinesi Araç Arabirimi’ne (JVMTI) yeni API eklendi. Örneklemenin ek yükü düşüktür ve sürekli etkinleştirilebilir. Java Uçuş Kaydedicisi (JFR) ile yığın ayırması izlenebilse de, JFR’deki örnekleme yöntemi yalnızca ayırmalar üzerinde çalışır. JFR uygulaması da ayırmaları kaçırabilir. Buna karşılık Java 11’deki yığın örneklemesi hem canlı hem de ölü nesneler hakkında bilgi sağlayabilir.
Uygulama Performansı İzleme (APM) satıcıları bu yeni özelliği kullanmaya başlamıştır ve Java Mühendislik Grubu Azure performans izleme araçlarıyla kullanım potansiyeli incelemektedir.
StackWalker [9]
Günlüğe kaydetme sırasında genellikle geçerli iş parçacığı için yığının anlık görüntüsünü alma işlemi kullanılır. Sorun yığın izlemesinin ne kadarının günlüğe kaydedileceği ve yığını izlemesinin hiç günlüğe kaydedilip kaydedilmeyeceğidir. Örneğin, birisi yalnızca yöntemden alınan belirli bir özel durum için yığın izlemesini görmek isteyebilir. StackWalker sınıfı (Java 9’da eklendi) yığının bir anlık görüntüsünü verir ve programcıya yığın izlemesini nasıl kullanacağı konusunda ayrıntılı denetim getiren yöntemler sağlar.
Çöp toplama [10]
Aşağıdaki çöp toplayıcılar Java 11'de kullanılabilir: Seri, Paralel, Çöp öncelikli ve Epsilon. Java 11’de varsayılan atık toplayıcı Garbage First Garbage Collector’dır (G1GC).
Diğer üç toplayıcı burada konuyu tamamlamak için belirtilmiştir. Z Garbage Collector (ZGC), duraklama sürelerini 10 ms’nin altında tutmayı deneyen eşzamanlı, düşük gecikme süreli bir toplayıcıdır. ZGC Java 11’de deneysel bir özellik olarak sağlanır. Shenandoah toplayıcısı, çalışan Java programıyla eşzamanlı olarak daha fazla atık toplama gerçekleştirme yoluyla GC duraklama sürelerini kısaltan düşük duraklama süreli bir toplayıcıdır. Shenandoah Java 12’de deneysel bir özelliktir ama Java 11’e de desteği eklenmiştir. Concurrent Mark and Sweep (CMS) toplayıcısı kullanılabilir ama Java 9’dan beri kullanım dışı bırakılmıştır.
JVM, ortalama kullanım örneği için GC varsayılanlarını ayarlar. Genellikle bu varsayılanlar ve diğer GC ayarları, uygulamanın gereksinimlerine göre en uygun aktarım hızı ve gecikme süresi için ayarlanmalıdır. GC’yi düzgün ayarlamak derin bir GC bilgisi gerektirir ve bu uzmanlık Microsoft Java Mühendislik Grubu tarafından sağlanır.
G1GC
Java 11’de varsayılan atık toplayıcı G1 atık toplayıcısıdır (G1GC). G1GC’nin amacı gecikme süresiyle aktarım hızı arasında bir denge tutturmaktır. G1 atık toplayıcısı yüksek olasılıkla duraklama süresi hedeflerine ulaşarak yüksek aktarım hızını başarmaya çalışır. G1GC, tam koleksiyonları önlemek için tasarlanmıştır, ancak eşzamanlı koleksiyonlar belleği yeterince hızlı geri kazanamadığında geri dönüş tam GC oluşur. Tam GC, genç ve karma toplamalarla aynı sayıda paralel çalışan iş parçacığı kullanır.
Paralel GC
Paralel toplayıcı Java 8’de varsayılan toplayıcıdır. Paralel GC, atık toplamayı hızlandırmak için birden çok iş parçacığı kullanan bir aktarım hızı toplayıcısıdır.
Epsilon [11]
Epsilon atık toplayıcısı ayırmaları işler ama belleği geri kazanmaz. Yığın tükendiğinde JVM kapatılır. Epsilon kısa süreli hizmetler ve atık içermediği bilinen uygulamalarda kullanışlıdır.
Docker kapsayıcıları için geliştirmeler [12]
Java 10’dan önce, kapsayıcı için ayarlanmış olan bellek ve CPU kısıtlamaları JVM tarafından tanınmıyordu. Örneğin Java 8’de JVM varsayılan yığın boyutu üst sınırı olarak temel konağın fiziksel belleğinin ¼ kadarını kullanıyordu. Java 10’dan başlayarak, JVM bellek ve CPU sınırlarını ayarlamak için kapsayıcı denetim grupları (cgroup) tarafından ayarlanan kısıtlamaları kullanır. Örneğin varsayılan yığın boyutu üst sınırı kapsayıcının bellek sınırının ¼ kadarıdır (m2G için 500 MB gibi).
Docker kapsayıcısı kullanıcılarına Java yığınında kullanılacak sistem belleği miktarı üzerinde daha ayrıntılı bir denetim sağlayacak JVM Seçenekleri de eklenmiştir.
Bu destek varsayılan olarak etkinleştirilir ve yalnızca Linux tabanlı platformlarda kullanılabilir.
Not
Cgroup etkinleştirme çalışmasının büyük bölümü jdk8u191 itibarıyla Java 8’de de kullanılabilir. Diğer geliştirmeler 8’de de desteklenecek duruma getirilmemiş olabilir.
Çok sürümlü jar dosyaları [13]
Java 11’de sınıf dosyalarının Java sürümüne özgü birden çok uyarlamasını içeren bir jar dosyası oluşturmak mümkündür. Çok sürümlü jar dosyaları, kitaplık geliştiricilerinin jar dosyalarının çeşitli sürümlerini göndermek zorunda kalmadan Java’nın birden çok sürümünü destekleyebilmesini mümkün kılar. Söz konusu kitaplıkların kullanıcıları için çok sürümlü jar dosyaları, belirli jar dosyalarını belirli çalışma zamanı hedefleriyle eşleştirme zorunluluğu sorununu çözer.
Çeşitli performans geliştirmeleri
JVM’de yapılan aşağıdaki değişiklikler performansı doğrudan etkiler.
JEP 197: Kesimli Kod Önbelleği [14] - Kod önbelleğini ayrı segmentlere böler. Bu segmentlere ayırma işlemi JVM belleği ayak izinin daha iyi denetlenmesini sağlar, derlenmiş yöntemleri tarama süresini kısaltır, kod önbelleğinin parçalanmasını önemli ölçüde azaltır ve performansı geliştirir.
JEP 254: Sıkıştırılmış Dizeler [15] - Karakter kodlamasına bağlı olarak dizenin iç gösterimini karakter başına iki bayttan karakter başına bir veya iki bayt olarak değiştirir. Dizelerin çoğunluğu ISO-8859-1/Latin-1 karakterleri içerdiğinden, bu değişiklik Dizeyi depolamak için gereken alan miktarını yarıya indirir.
JEP 310: Uygulama Class-Data Paylaşımı [16] - Class-Data Paylaşımı, arşivlenmiş sınıfların çalışma zamanında belleğe eşlenmesine izin vererek başlatma süresini azaltır. Uygulama Sınıf Verileri Paylaşımı uygulama sınıflarının CDS arşivine yerleştirilmesine olanak tanıyarak sınıf verileri paylaşımının kapsamını genişletir. Birden çok JVM aynı arşiv dosyasını paylaştığında bellekten tasarruf edilir ve bir bütün olarak sistem yanıt süresi gelişir.
JEP 312: Thread-Local El Sıkışmaları [17] - Genel bir VM güvenli noktası gerçekleştirmeden iş parçacıklarında geri çağırma yürütmeyi mümkün kılar ve bu da vm'nin genel güvenli nokta sayısını azaltarak daha düşük gecikme süresi elde etmesine yardımcı olur.
Derleyici İş Parçacıklarının Gecikmeli Ayrılması [18] - Katmanlı derleme modunda, VM çok sayıda derleyici iş parçacığı başlatır. Bu, birçok CPU’su olan sistemlerde varsayılan moddur. Bu iş parçacıkları kullanılabilir bellekten veya derleme isteklerinin sayısından bağımsız olarak oluşturulur. İş parçacıkları boşta olduklarında bile bellek tüketir (bu da neredeyse her zaman anlamına gelir) ve kaynakların verimsiz kullanımına yol açar. Bu sorunu çözmek için, başlatma sırasında her türden tek bir derleyici iş parçacığı başlatılacak şekilde uygulama değiştirilmiştir. Ek iş parçacıklarını başlatma ve kullanılmayan iş parçacıklarını kapatma işlemleri dinamik olarak işlenir.
Çekirdek kitaplıklarda yapılan aşağıdaki değişiklikler, yeni veya değiştirilmiş kodun performansını etkiler.
JEP 193: Değişken Tanıtıcıları [19] - Nesne alanları ve dizi öğeleri üzerinde çeşitli java.util.concurrent.atomic ve sun.misc.Unsafe işlemlerinin eşdeğerlerini çağırmak için standart bir araç, bellek sıralamanın ayrıntılı denetimi için standart bir çit işlemleri kümesi ve başvurulan bir nesnenin güçlü bir şekilde erişilebilir kalmasını sağlamak için standart bir ulaşılabilirlik çit işlemi tanımlar.
JEP 269: Koleksiyonlar için Convenience Factory Yöntemleri [20] - Az sayıda öğe içeren koleksiyon ve harita örnekleri oluşturmayı kolaylaştırmak için kitaplık API'lerini tanımlar. Koleksiyon arabirimleri üzerinde küçük, değiştirilemez koleksiyon örnekleri oluşturan statik fabrika yöntemleri. Bu örnekler doğal olarak daha verimlidir. API’ler sıkıştırılmış bir şekilde temsil edilen ve sarmalayıcı sınıfı olmayan koleksiyonlar oluşturur.
JEP 285: Spin-Wait İpuçları [21] - Java'nın çalışma zamanı sistemine bir dönüş döngüsünde olduğunu belirtmesini sağlayan API sağlar. Bazı donanım platformları iş parçacığının meşgul-bekleme durumunda olduğuna ilişki yazılım göstergesinden yararlanır.
JEP 321: HTTP İstemcisi (Standart) [22]- HTTP/2 ve WebSocket uygulayan ve eski HttpURLConnection API'sinin yerini alan yeni bir HTTP istemci API'sini sağlar.
Başvurular
[1] Oracle Corporation, "Java Development Kit 9 Sürüm Notları", (Çevrimiçi). Sağlandığı Konum: https://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html. (13 Kasım 2019’da Erişildi).
[2] Oracle Corporation, "Java Development Kit 10 Sürüm Notları", (Çevrimiçi). Sağlandığı Konum: https://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html. (13 Kasım 2019’da Erişildi).
[3] Oracle Corporation, "Java Development Kit 11 Sürüm Notları", (Çevrimiçi). Sağlandığı Konum: https://www.oracle.com/technetwork/java/javase/11u-relnotes-5093844.html. (13 Kasım 2019’da Erişildi).
[4] Oracle Corporation, "Project Jigsaw", 22 Eylül 2017. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/projects/jigsaw/. (13 Kasım 2019’da Erişildi).
[5] Oracle Corporation, "JEP 328: Flight Recorder," 9 Eylül 2018. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/328. (13 Kasım 2019’da Erişildi).
[6] Oracle Corporation, "Mission Control", 25 Nisan 2019. (Çevrimiçi). Sağlandığı Konum: https://wiki.openjdk.java.net/display/jmc/Main. (13 Kasım 2019’da Erişildi).
[7] Oracle Corporation, "JEP 158: Unified JVM Logging," 14 Şubat 2019. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/158. (13 Kasım 2019’da Erişildi).
[8] Oracle Corporation, "JEP 331: Low-Overhead Yığın Profili Oluşturma," 5 Eylül 2018. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/331. (13 Kasım 2019’da Erişildi).
[9] Oracle Corporation, "JEP 259: Stack-Walking API," 18 Temmuz 2017. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/259. (13 Kasım 2019’da Erişildi).
[10] Oracle Corporation, "JEP 248: G1'i Varsayılan Çöp Toplayıcı Yap", 12 Eylül 2017. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/248. (13 Kasım 2019’da Erişildi).
[11] Oracle Corporation, "JEP 318: Epsilon: A No-Op Çöp Toplayıcısı," 24 Eylül 2018. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/318. (13 Kasım 2019’da Erişildi).
[12] Oracle Corporation, "JDK-8146115: Docker kapsayıcı algılama ve kaynak yapılandırması kullanımını geliştirme", 16 Eylül 2019. (Çevrimiçi). Sağlandığı Konum: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115. (13 Kasım 2019’da Erişildi).
[13] Oracle Corporation, "JEP 238: Multi-Release JAR Files," 22 Haziran 2017. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/238. (13 Kasım 2019’da Erişildi).
[14] Oracle Corporation, "JEP 197: Segmented Code Cache", 28 Nisan 2017. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/197. (13 Kasım 2019’da Erişildi).
[15] Oracle Corporation, "JEP 254: Compact Strings", 18 Mayıs 2019. (Çevrimiçi). Sağlandığı Konum: http://openjdk.java.net/jeps/254. (13 Kasım 2019’da Erişildi).
[16] Oracle Corporation, "JEP 310: Application Class-Data Sharing," 17 Ağustos 2018. (Çevrimiçi). Sağlandığı Konum: https://openjdk.java.net/jeps/310. (13 Kasım 2019’da Erişildi).
[17] Oracle Corporation, "JEP 312: Thread-Local Handshakes," 21 Ağustos 2019. (Çevrimiçi). Sağlandığı Konum: https://openjdk.java.net/jeps/312. (13 Kasım 2019’da Erişildi).
[18] Oracle Corporation, "JDK-8198756: Derleyici iş parçacıklarının gecikmeli ayrılması," 29 Ekim 2018. (Çevrimiçi). Sağlandığı Konum: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8198756. (13 Kasım 2019’da Erişildi).
[19] Oracle Corporation, "JEP 193: Değişken Tanıtıcıları", 17 Ağustos 2017. (Çevrimiçi). Sağlandığı Konum: https://openjdk.java.net/jeps/193. (13 Kasım 2019’da Erişildi).
[20] Oracle Corporation, "JEP 269: Convenience Factory Methods for Collections," 26 Haziran 2017. (Çevrimiçi). Sağlandığı Konum: https://openjdk.java.net/jeps/269. (13 Kasım 2019’da Erişildi).
[21] Oracle Corporation, "JEP 285: Spin-Wait İpuçları", 20 Ağustos 2017. (Çevrimiçi). Sağlandığı Konum: https://openjdk.java.net/jeps/285. (13 Kasım 2019’da Erişildi).
[22] Oracle Corporation, "JEP 321: HTTP İstemcisi (Standart)," 27 Eylül 2018. (Çevrimiçi). Sağlandığı Konum: https://openjdk.java.net/jeps/321. (13 Kasım 2019’da Erişildi).