Android çalışma zamanı (ART), Android 8.0 sürümünde önemli ölçüde iyileştirildi. Aşağıdaki liste, cihaz üreticilerinin ART'tan bekleyebileceği geliştirmeleri özetlemektedir.
Eşzamanlı sıkıştırmalı çöp toplayıcı
Google I/O'da duyurulduğu üzere ART, Android 8.0'da yeni bir eşzamanlı sıkıştırmalı çöp toplayıcıya (GC) sahiptir. Bu toplayıcı, GC her çalıştırıldığında ve uygulama çalışırken, iş parçacığı köklerini işlemek için yalnızca kısa bir duraklamayla yığını sıkıştırır. İşte faydaları:
- GC yığını her zaman sıkıştırır: Android 7.0'a kıyasla ortalama %32 daha küçük yığın boyutları.
- Sıkıştırma, iş parçacığı yerel çarpma işaretçisi nesne tahsisine olanak tanır: Tahsisler, Android 7.0'a göre %70 daha hızlıdır.
- H2 karşılaştırması için Android 7.0 GC'ye kıyasla %85 daha kısa duraklama süreleri sunar.
- Duraklatma süreleri artık yığın boyutuna göre ölçeklenmiyor; uygulamalar, jank konusunda endişelenmeden büyük yığınları kullanabilmelidir.
- GC uygulama ayrıntısı - Okuma engelleri:
- Okuma engelleri, okunan her nesne alanı için yapılan az miktardaki iştir.
- Bunlar derleyicide optimize edilmiştir ancak bazı kullanım durumlarını yavaşlatabilir.
Döngü optimizasyonları
ART tarafından Android 8.0 sürümünde çok çeşitli döngü optimizasyonları kullanılmaktadır:
- Sınır kontrolü elemeleri
- Statik: aralıkların derleme zamanında sınırlar dahilinde olduğu kanıtlanmıştır
- Dinamik: çalışma zamanı testleri döngülerin sınırlar içinde kalmasını sağlar (aksi halde deopt)
- İndüksiyon değişkeni eliminasyonları
- Ölü indüksiyonu kaldırın
- Yalnızca döngüden sonra kullanılan tümevarımı kapalı biçimli ifadelerle değiştirin
- Döngü gövdesi içindeki ölü kodun ortadan kaldırılması, ölü hale gelen tüm döngülerin kaldırılması
- Mukavemet azalması
- Döngü dönüşümleri: ters çevirme, değiştirme, bölme, açma, tek modüler vb.
- SIMDizasyon (vektörizasyon da denir)
Döngü iyileştirici, ART derleyicisindeki kendi optimizasyon geçişinde bulunur. Çoğu döngü optimizasyonu, başka yerlerdeki optimizasyonlara ve basitleştirmelere benzer. CFG'yi her zamankinden daha ayrıntılı bir şekilde yeniden yazan bazı optimizasyonlarda zorluklar ortaya çıkar, çünkü çoğu CFG yardımcı programı (bkz. node.h) bir CFG'yi yeniden yazmaya değil, oluşturmaya odaklanır.
Sınıf hiyerarşisi analizi
Android 8.0'daki ART, sınıf hiyerarşilerinin analiz edilmesiyle oluşturulan bilgilere dayanarak sanal çağrıları doğrudan çağrılara dönüştüren bir derleyici optimizasyonu olan Sınıf Hiyerarşi Analizi'ni (CHA) kullanır. Sanal aramalar, vtable araması etrafında uygulandıkları için pahalıdır ve birkaç bağımlı yük alırlar. Ayrıca sanal çağrılar satır içi olamaz.
İlgili geliştirmelerin bir özetini burada bulabilirsiniz:
- Dinamik tek uygulamalı yöntem durum güncellemesi - Sınıf bağlama süresinin sonunda, vtable doldurulduğunda, ART, süper sınıfın vtable'ıyla giriş bazında bir karşılaştırma gerçekleştirir.
- Derleyici optimizasyonu - Derleyici, bir yöntemin tek uygulama bilgisinden yararlanacaktır. A.foo yönteminde tek uygulama bayrağı ayarlanmışsa, derleyici sanal çağrıyı doğrudan çağrıya dönüştürecek ve sonuç olarak doğrudan çağrıyı satır içi yapmaya çalışacaktır.
- Derlenmiş kodun geçersiz kılınması - Ayrıca, tek uygulama bilgisi güncellendiğinde sınıf bağlama süresinin sonunda, daha önce tek uygulama olan ancak bu durum artık geçersiz kılınan A.foo yöntemi varsa, A yönteminin geçerli olduğu varsayımına bağlı olan tüm derlenmiş kodlar. foo'nun derlenmiş kodlarının geçersiz kılınması için tek uygulama ihtiyaçları vardır.
- Optimizasyonun kaldırılması - Yığındaki canlı derlenmiş kod için, doğruluğu garanti etmek üzere geçersiz kılınan derlenmiş kodun yorumlayıcı moduna zorlanması amacıyla optimizasyonun düşürülmesi başlatılacaktır. Senkron ve asenkron deoptimizasyon melezi olan yeni bir deoptimizasyon mekanizması kullanılacaktır.
.oat dosyalarındaki satır içi önbellekler
ART artık satır içi önbellekler kullanıyor ve yeterli verinin bulunduğu çağrı sitelerini optimize ediyor. Satır içi önbellek özelliği, ek çalışma zamanı bilgilerini profillere kaydeder ve bunu önceden derlemeye dinamik optimizasyonlar eklemek için kullanır.
Dex düzeni
Dexlayout, dex dosyalarını analiz etmek ve bunları bir profile göre yeniden sıralamak için Android 8.0'da tanıtılan bir kütüphanedir. Dexlayout, cihazda boşta bakım derlemesi sırasında dex dosyasının bölümlerini yeniden sıralamak için çalışma zamanı profil oluşturma bilgilerini kullanmayı amaçlamaktadır. Programlar, dex dosyasının sıklıkla birlikte erişilen bölümlerini bir arada gruplandırarak, gelişmiş konum sayesinde daha iyi bellek erişim modellerine sahip olabilir, RAM tasarrufu sağlayabilir ve başlatma süresini kısaltabilir.
Profil bilgileri şu anda yalnızca uygulamalar çalıştırıldıktan sonra mevcut olduğundan, dexlayout, boşta bakım sırasında dex2oat'ın cihaz üzerindeki derlemesine entegre edilir.
Dex önbelleğini kaldırma
Android 7.0'a kadar DexCache nesnesi, DexFile'daki belirli öğelerin sayısıyla orantılı dört büyük diziye sahipti:
- dizeler (DexFile::StringId başına bir referans),
- türler (DexFile::TypeId başına bir referans),
- yöntemler (DexFile::MethodId başına bir yerel işaretçi),
- alanlar (DexFile::FieldId başına bir yerel işaretçi).
Bu diziler daha önce çözdüğümüz nesnelerin hızlı bir şekilde alınması için kullanıldı. Android 8.0'da, yöntemler dizisi dışındaki tüm diziler kaldırılmıştır.
Tercüman performansı
Tercüman performansı, derleme dilinde yazılmış temel bir getirme/kod çözme/yorumlama mekanizmasına sahip bir tercüman olan "mterp"in kullanıma sunulmasıyla Android 7.0 sürümünde önemli ölçüde iyileştirildi. Mterp, hızlı Dalvik yorumlayıcısından sonra modellenmiştir ve arm, arm64, x86, x86_64, mips ve mips64'ü destekler. Hesaplamalı kod açısından, Art'ın mterp'si kabaca Dalvik'in hızlı yorumlayıcısıyla karşılaştırılabilir. Bununla birlikte, bazı durumlarda önemli ölçüde ve hatta çarpıcı biçimde daha yavaş olabilir:
- Performansı çağırın.
- İp manipülasyonu ve Dalvik'in özü olarak kabul edilen yöntemlerin diğer yoğun kullanıcıları.
- Daha yüksek yığın bellek kullanımı.
Android 8.0 bu sorunları gideriyor.
Daha fazla satır içi
Android 6.0'dan bu yana, ART aynı dex dosyalarındaki herhangi bir çağrıyı satır içi yapabilir, ancak yalnızca farklı dex dosyalarından satır içi yaprak yöntemlerini kullanabilir. Bu sınırlamanın iki nedeni vardı:
- Başka bir dex dosyasından satır içi oluşturma, arayanın dex önbelleğini yeniden kullanabilen aynı dex dosyası satır içi işleminden farklı olarak, diğer dex dosyasının dex önbelleğinin kullanılmasını gerektirir. Statik çağrılar, dize yükleme veya sınıf yükleme gibi birkaç talimat için derlenmiş kodda dex önbelleğine ihtiyaç vardır.
- Yığın haritaları yalnızca geçerli dex dosyasındaki bir yöntem dizinini kodluyor.
Bu sınırlamaları gidermek için Android 8.0:
- Derlenmiş koddan dex önbellek erişimini kaldırır ("Dex önbelleğini kaldırma" bölümüne de bakın)
- Yığın haritası kodlamasını genişletir.
Senkronizasyon iyileştirmeleri
ART ekibi MonitorEnter/MonitorExit kod yollarını ayarladı ve ARMv8'deki geleneksel bellek engellerine olan bağımlılığımızı azalttı ve bunları mümkün olduğunca daha yeni (edinme/bırakma) talimatlarıyla değiştirdi.
Daha hızlı yerel yöntemler
@FastNative
ve @CriticalNative
ek açıklamaları kullanılarak Java Yerel Arayüzüne (JNI) daha hızlı yerel çağrılar yapılabilir. Bu yerleşik ART çalışma zamanı optimizasyonları, JNI geçişlerini hızlandırır ve artık kullanımdan kaldırılan !bang JNI gösteriminin yerini alır. Ek açıklamaların yerel olmayan yöntemler üzerinde hiçbir etkisi yoktur ve yalnızca bootclasspath
yolundaki Java Dil kodunu platformlamak için kullanılabilir (Play Store güncellemesi yoktur).
@FastNative
ek açıklaması statik olmayan yöntemleri destekler. Bir yöntem bir jobject
parametre veya dönüş değeri olarak erişiyorsa bunu kullanın.
@CriticalNative
ek açıklaması, aşağıdaki kısıtlamalarla yerel yöntemleri çalıştırmak için daha da hızlı bir yol sağlar:
- Yöntemler statik olmalıdır; parametreler, dönüş değerleri veya örtülü
this
için nesneler olmamalıdır. - Yerel yönteme yalnızca ilkel türler aktarılır.
- Yerel yöntem, işlev tanımında
JNIEnv
vejclass
parametrelerini kullanmaz. - Yöntemin, dinamik JNI bağlantısına güvenmek yerine
RegisterNatives
kaydedilmesi gerekir.
@FastNative
yerel yöntem performansını 3 kata kadar, @CriticalNative
ise 5 kata kadar artırabilir. Örneğin, Nexus 6P cihazında ölçülen bir JNI geçişi:
Java Yerel Arayüzü (JNI) çağrısı | Yürütme süresi (nanosaniye cinsinden) |
---|---|
Düzenli JNI | 115 |
!bang JNI | 60 |
@FastNative | 35 |
@CriticalNative | 25 |