Android Performance Part3-SparseArray Benchmark

Kerim Fırat
4 min readApr 26, 2021

Java-Android Performance Part1 makalesine buradan erişebilirsiniz.
Java-Android Performance Part2 makalesine buradan erişebilirsiniz.

Mobil uygulamalar geliştirirken enerji ve memory tüketiminin gözetilmesi konusu giderek daha da kritik hale geliyor.Gelişigüzel geliştirme yapmak ciddi maliyetleri beraberinde getiriyor. Bu kritik maliyetlerin en tepesine enerji ve memory tüketimi konulabilir. Dolayısıyla performans odaklı kod geliştirmek en önemli kriterdir.

Geliştirici gözüyle performans konusunu temel düzeyde ele aldığımızda,veri yapıları ve bu yapıları doğru ve yerinde kullanmak oldukça etkin bir kabiliyettir. Örneğin veri tipi tanımlarken,kullanacağımız veri boyutuna uygun tip tanımlaması yapmak önemlidir. Veya bir array kullanmak gerektiğinde yine aynı şekilde kullanacağımız veri boyutuna göre array oluşturmak veya SDK tarafından sağlanan Array class’ları doğru kullanmak önemlidir. Örneğin SDK tarafından sağlanan birçok Array arasından seçim yapmak için çok fazla karşılaştırma sonucu incelemek gerekebilir. Ve tabi mevcut karşılaştırmalar belli durumlarda ve/veya veri boyutlarını aştıklarında farklı sonuçlar üretebiliyor. Dolayısıyla çoğu için kesin olarak bir sonuç söylemek güçtür.
Bu nedenle çok fazla kaynak araştırması yapmak ve özellikle kendini ispatlamış Open Source projelerin kaynak kodlarını referans alarak sonuç belirlemek en etkin yaklaşımdır. Nitekim incelemelerde bulunduğum bazı Open Source projelerde bu yaklaşım görülüyor ve uygulanıyor.

Aslında performans konularını işlerken,özellikle memory tarafında bol şikayet alan bir Open Source proje seçmek ve bu proje üzerinden fix’leme yaparak karşılaştırma yapmayı planlıyorum. Ve böylece daha kapsamlı sonuçlar üzerinden konuşabileceğiz.

Benchmark(Karşılaştırma)

Android tarafında performans konularını işelemeye başlarken özellikle SparseArray ve buna bağlı diğer Sparse class’lara değindik. Part2'de SparseArray’a ait kaynak kodları inceledik. Bu incelememizde ise SparseArray’ı biraz daha açarak HashMap ile karşılaştıracağız.

Karşılaştırma yapmadan önce,standart Java yapısında ve Android yapısında yer alan class’lara yer verelim.

Standart Java Yapısı
HashMap<K, V>
HashMap<Integer, V>
HashMap<Integer, Boolean>
HashMap<Integer, Integer>
HashMap<Integer, Long>
HashMap<Long, V>

Android Yapısı
ArrayMap<K, V>
SparseArray<V>
SparseBooleanArray
SparseIntArray
SparseLongArray
LongSparseArray<V>

Yukarıda verilen Android yapısı Standart Java Yapısı içinde bulunmamaktadır.

Hangisi Ve Neden Yavaş?
Kaynak kodlar üzerinden inceleme yaparken belli durumlarda SparseArray’ın yavaş olduğunu belirtmiştik.
SparseArray’ın yavaş olduğu en belirgin durum,array içerisinde belli bir limitten fazla öğe(item) bulundurmaktır.Bu limit 100bin öğe civarı olarak çeşitli kaynaklarda dile getiriliyor.Ancak bu limite yaklaştıkça dizi sıkılaştırma süreçleri nedeniyle belli bir performans kaybı benim de yaptığım bazı testlerde görülüyor.Zaten genel olarak 10bin’den fazla öğe içeren yapıların kullanılması tavsiye edilmiyor.

NOT: HashMap ve SparseArray içeren kapsamlı bir analizi Android Open Source projesi üzerinden yürütüyorum. Bu çalışmayı tamamladığımda ek part olarak paylaşacağım.

Ancak HashMap genel olarak SparseArray ile kıyasla yavaş çalışmaktadır. Bunun başlıca sebepleri bulunmaktadır. Bu sebeplerin ilki Autoboxing kavramıdır. Zaten bu kavramı önceki yazılarda inceledik.
Yavaş olmasının ikinci sebebi ise büyük boyutlarda dizi tahsisi yapıyor olmasıdır. Büyük boyutlarda dizi tahsisi yapmasının da sebebi ise key hash çarpışma olasılıklarıyla mücadele etmektir.

Her iki dizi arasında yüksek(+10bin) limitlere yaklaşıldığında,HashMap öğe ekleme işleminde hızlı çalışırken,öğre çağırma işleminde ise SparseArray yüksek performans göstermektedir.

Hangisini Kullanmalıyım?
Konu aldığımız veri yapısının artılarını ve eksilerini tartışan çeşitli kaynaklar internette mevcuttur.
Öncesinde de belirttiğim gibi,çeşitli durumlarda ve çeşitli veri boyutlarında bu yapıların sonuçları değişmektedir. Dolayısıyla kaynakları incelerken bu durumları gözönünde bulundurmamız gerekir.

Bu tartışma kaynaklarından birisi de “Exploring hidden java costs” konuşmasında işleniyor. Bu kaynak içeriğinde HashMap ve SparseArray classların nasıl çalıştıkları ve avantajlarından bahsediliyor. Bu kaynak,ikisi arasında karşılaştırma yaparken faydalanacağımız kaynaklardan biri olarak ele alınabilir.

Eğer Open Source projeleri inceliyor ve/veya katkı yapıyorsanız,SparseArray’ın HashMap’a alternatif olarak ne zaman kullanıldığıyla alakalı notlar ve fix’ler görebilirsiniz.

Bu kaynakta farklı bir yaklaşımla karşılaştırma sonuçlarını bulabilirsiniz. Burada 1 ile 1,000,000 arası dizi boyutları üzerinde yapılan karşılaştırmalar mevcut. Kaynak eski ancak bu karşılaştırmanın eski cihazlar üzerinden etkisini görmek için faydalı olabileceğini düşünüyorum.

İncelenmesi gereken bir diğer kaynak ise greenspector’dir.
Aşağıda bu kaynağa ait SparseArray sonuçlarını gösteren bir görsele yer verilmiştir.Bu sonuçlar(Enerji,bellek tüketimi ve performans), sırasıyla 100,1000,10.000 ve 100.000 öğe ekleme ve çağırma işlemlerine ait verileri göstermektedir.

greenspector.com

Yukarıdaki sonuçlara göre 100 öğre için sonuçlar SparseArray ve HashMap birbirine yakındır. Ancak SparseArray öğreleri okumak için enerjiyi verimli kullanıyor ve hafıza kazancı sağlıyor.
Öğeleri yazma konusunda enerji ve zaman tasarrufu bakımından avantaj burda HashMap’dan yanadır. Ancak 1000 öğeden itibaren dengeler SparseArray lehine gelişmektedir.

Bir diğer karşılaştırma ise SparseArray bağlantılı “SparseBooleanArray, SparseIntArray, SparseLongArray” classlar üzerinden yapılmıştır.
Aşağıda bu görsele yer veriliyor.

greenspector.com

Bu 3 class için sonuçlar düşük öğe limitlerinde SparseArray ile benzerdir ancak yüksek öğe limitlerinde kazanlar daha da belirgindir.

Son görsel “LongSparseArray”’a aittir.Bu görsele aşağıda yer verilmiştir:

greenspector.com

LongSparseArray’ın durumu diğerlerinden farklıdır. Düşük limitler için enerji ve zamanda %25,bellekte %5 kazanç elde ediliyor. Veri boyutu arttığında bu kazançlar da artar.

LongSparseArray 1000 öğe için %59 daha az enerji tüketir,%62 daha hızlıdır ve yalnızca %2 daha az bellek tüketiyor. Ancak öğe limiti 10.000 ve üzeri için enerji ve zaman kazanımı benzerdir(%75).

Ancak 100 öğe okumada LongSparseArray HashMap’ten biraz daha fazla enerji tüketiyor.Bu oran %8 civarındadır. Ancak 1000 öğede %15 daha az enerji tükettiği ve %20 daha hızlı olduğu için yine etkilidir.
Limitler 10.000'i gösterdiğinde ise %36 enerji tasarrufu sağlar ve uygulama süresi %52 oranda azalır.

Öğe yazarken 100.000 ile 10.000 sonuçları benzerdir. Bu durumda %41 enerji kazancı ve %43 zaman tasarrufu elde ediliyor.

Sonuç olarak hangisi kullanılmalıdır sorusuna cevap kabaca verilebilir.
Ancak AOSP üzerinde yürüttüğüm benchmark çalışmasını tamamlamadan bu konuda size kesin bir öneri yapmayacağım.Yukarıdaki sonuçları inceleyerek tercih yapabilirsiniz. Fakat benim tercihim genellikle SparseArray’dan yana olmuştur.

KAYNAKLAR:
https://files.speakerdeck.com/presentations/5ef7038a1106403bb53a34ff4bdedc4e/20160728-360AnDev-ExploringJavasHiddenCosts-ForExport.pdf
https://greenspector.com/en/android-should-you-use-hashmap-or-sparsearray/

-end of

--

--

Kerim Fırat
Kerim Fırat

Written by Kerim Fırat

Senior Android Platform(AOSP,AAOS) Architect,Open Source Contributor | Turkey Java User Group Vice Chairman | Author

No responses yet