Sunday, July 16, 2017

Java Sanal Makinasında Sınıf Yükleme Başarımının İyileştirilmesi


Java uygulamaları çalışabilmek için Java Sanal Makinasına (=JSM)  ihtiyaç duyarlar. JSM içinde uygulamanın başarımını belirleyen üç temel bileşen yer alır: 
  • JIT (Just-In-Time) Derleyici
JIT derleyici bytecode’ları JSM’nin üzerinde çalıştığı platformun anlayacağı, örneğin Intel komutlarına dönüştürür. Üstelik bunu yaparken devingen en iyileme de yapar. Bunun için uygulamanın basit bir kesitini (=profiling) alır. Bu kesit bilgisine göre onlarca en iyileme tekniğinden hangilerini uygulayacağına karar verir. 
  • Çöp Toplayıcı
Yürütme zamanında ortaya çıkan bellek ihtiyacını ise Heap olarak adlandırılan bir bellek alanından new işlecini kullanarak karşılıyoruz. new ile aldığımız alanı işimiz bitince geri vermemiz gerekmez. Bu alanın yönetiminden Çöp Toplayıcı sorumludur. Çöp toplayıcı, temel olarak Heap’de canlı nesneleri saptar ve ölü nesneleri yeniden kullanılabilir bellek alanlarına dönüştürür. Çöp toplayıcı geliştiricinin üzerinden önemli bir yükü alır. Ancak bunun için yürütme zamanında bir bedel ödenir. HotSpot içinde çok sayıda çöp toplayıcı yer alır. Bunlardan hangilerinin seçileceği ve en iyilenmesi önemli bir konudur. JDK 7u4 ile birlikte G1GC (Garbage First) olarak adlandırılan yeni bir çöp toplayıcısı geldi. Java 8'de G1GC olgunlaştı ve nihayet Java 9 ile birlikte varsayılan çöp toplayıcısı G1GC oluyor.
  • Sınıf Yükleyici (=class loader)
Java, nesneye dayalı bir programlama dilidir. Bu nedenle, her kavramı sınıf ile modelliyoruz ve sınıflardan yarattığımız nesneler ile de problemleri çözmeye çalışıyoruz. Dolayısı ile bir Java uygulaması, çok sayıda sınıftan oluşur. Sınıf yükleyicisinin görevi, sınıfları ihtiyaç duyuldukça belleğe, bellekte özel bir alana yüklemektir. Java 7'ye kadar bu alanın adı Perm[enant] Gen[eration], Java 8'den itibaren ise Meta Space olarak adlandırılmaktadır. Uygulamayı çalıştırdığımızda, sınıf yükleyicisi sınıfların hepsini birden tek bir seferde bu alana yüklenmez, biraz tembellik eder. İlk ihtiyaç duyulduğunda sınıf yüklenir. Sınıfların yüklenmesi programatik olarak da yönlendirilebilir. Sınıf Yükleyici, sadece sınıfı belleğe yüklemez, önce class dosya formatına uygunluğunu sınar, güvenlik kontrolü yapar ve nihayetinde bu denetimlerden geçebilirse belleğe yükler. Sınıf yüklemenin başarımı, ağırlıklı olarak, uygulamanın açılış süresi başarımını etkiler. Java 7'den itibaren Sınıf Yükleyici birden fazla iplik (=thread) tarafından paralel olarak çalıştırılabilir.
Sınıf yükleme başarımını arttırmak için uygulayabileceğimiz iki yöntem bulunuyor:
  • Güvenlik Kontrolünü kaldırmak
Eğer jar dosyaları uzaktan yüklenmiyorsa ve işletim sisteminin güvenliği sağlanmışsa Sınıf Yükleyicisinden bu adımı atlamasını isteyebiliriz. Bunun için uygulamayı başlatırken -Xverify:none seçeneğini sağlamamız yeterli olacaktır. Aşağıda Spring MVC ve Spring Data çatılarının kullanıldığı bir Spring Boot uygulamasının açılış zamanlarına ilişkin istatistiksel bilgiler paylaşılmıştır. Uygulama -Xverify:none seçeneği kullanılmadan, beş kere çalıştırıldığında, açılış süreleri aşağıdaki gibi gerçekleşmiştir:
Started SpringBootApplication in 7.381 seconds (JVM running for 8.275)
Started SpringBootApplication in 8.409 seconds (JVM running for 9.436)
Started SpringBootApplication in 7.559 seconds (JVM running for 8.449)
Started SpringBootApplication in 7.306 seconds (JVM running for 8.258)
Started SpringBootApplication in 7.97 seconds  (JVM running for 8.856)
Uygulama yine beş defa, bu kez -Xverify:none seçeneği ile başlatıldığında, açılış süreleri aşağıdaki gibi gerçekleşmiştir:
Started SpringBootApplication in 7.01  seconds (JVM running for 7.908)
Started SpringBootApplication in 6.889 seconds (JVM running for 7.746)
Started SpringBootApplication in 6.733 seconds (JVM running for 7.572)
Started SpringBootApplication in 6.673 seconds (JVM running for 7.761)
Started SpringBootApplication in 6.741 seconds (JVM running for 7.556)

Açılış süresi karşılaştırması
Sınıf yükleyicinin .class dosyalarını yüklerken, güvenlik denetimi özelliği kapatılırsa, açılış süresi ortalama 0.94 saniye kadar kısalmaktadır. Bu değer açılış süresinde %10'a kadar ulaşan bir iyileşme anlamına gelmektedir.
  • Class Data Sharing (CDS)
Eğer bir makinada çok sayıda Java uygulaması çalışıyorsa, uygulamalar arasında sınıf metadata bilgisi paylaşılabilinir. Bunun için sınıf metadatasını bir kez oluşturmak gerekir. JDK 8u40'dan önce sadece JDK içinde yer alan temel sınıflar için sınıf metadata paylaşımı mümkündü. JDK 8u40'dan itibaren sınıf metadatasının paylaşılmasını istediğimiz sınıfların listesini Java Sanal Makinasına verebiliyoruz. Uygulamanın eriştiği sınıfların listesini almak için uygulamayı bir kez -XX:DumpLoadedClassList seçeneği ile çalıştırmak ve sınıf listesini diske kaydetmek gerekir:
c:\tmp>java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
c:\tmp>java -XX:DumpLoadedClassList=list.txt -jar Java2D.jar
Ardından sınıf metadatasını aşağıdaki komutla yaratabiliriz:
c:\tmp>java -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:SharedClassListFile=list.txt -Xshare:dump
Allocated shared space: 37879808 bytes at 0x0000000800000000
Loading classes to share ...
Loading classes to share: done.
Rewriting and linking classes ...
Rewriting and linking classes: done
Number of classes 2284
    instance classes   =  2270
    obj array classes  =     6
    type array classes =     8
Calculating fingerprints ... done.
Removing unshareable information ... done.
Shared Lookup Cache Table Buckets = 8216 bytes
Shared Lookup Cache Table Body = 64736 bytes
ro space:   6381128 [ 36.5% of total] out of  16777216 bytes [38.0% used] at 0x0000000800000000
rw space:   9590512 [ 54.9% of total] out of  16777216 bytes [57.2% used] at 0x0000000801000000
md space:   1477592 [  8.5% of total] out of   4194304 bytes [35.2% used] at 0x0000000802000000
mc space:     34053 [  0.2% of total] out of    131072 bytes [26.0% used] at 0x0000000802400000
total   :  17483285 [100.0% of total] out of  37879808 bytes [46.2% used]
Artık uygulamayı CDS özelliği açık olacak şekilde başlatabiliriz:
c:\tmp>start java -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -Xshare:on -jar Java2D.jar

No comments:

Post a Comment