Bit eşlem nesneleri, genellikle bir uygulamanın bellekte kaplanan yerine en büyük katkıyı sağlayan tek öğelerdir. Uygulama simgeleri, bildirim resimleri veya medya içerikleri gibi durumlarda verimsiz bit eşlem işleme, hızlı bir şekilde bellek yetersizliği (OOM) hatalarına ve sistem genelinde bellek baskısına yol açabilir.
Bit eşlem yapılandırmaları ve piksel verileri
Bit eşlemin kullandığı bellek miktarı öncelikle boyutlarına (genişlik × yükseklik) ve yapılandırmasına (Bitmap.Config) göre belirlenir.
Yapılandırma, her pikseli temsil etmek için kaç bayt kullanıldığını tanımlar:
| Yapılandırma | Piksel Başına Bayt Sayısı | Açıklama |
|---|---|---|
ALPHA_8 |
1 | Yalnızca alfa (şeffaflık) kanalı. Maskeler için kullanışlıdır. |
RGB_565 |
2 | Kırmızı (5 bit), Yeşil (6 bit), Mavi (5 bit). Alfa yok. Yüksek renk doğruluğunun önemli olmadığı opak görüntüler için uygundur. |
ARGB_8888 |
4 | Alfa, Kırmızı, Yeşil, Mavi (her biri 8 bit). Varsayılan ve en yaygın kullanılan seçenektir. |
RGBA_F16 |
8 | Yarım duyarlıklı kayan nokta. Geniş gamlı ve HDR içeriklerde kullanılır. |
HARDWARE |
Yok | Ekran kartı belleğinde (gralloc/DMABuf) saklanır. Donanım Bit Eşlemleri başlıklı makaleyi inceleyin. |
Bellek Formülü: Memory (Bytes) = Width × Height × Bytes Per Pixel
Örneğin, 1080p cihazda (1920x1080) ARGB_8888 olan tam ekran bir resim için: 1920 × 1080 × 4 bayt ≈ 8,3 MB gerekir.
Yığın bit eşlemleri ve paylaşılan bit eşlemler
Yığın bit eşlemleri (yerel yığın)
Modern Android'de (8.0 ve sonraki sürümler) bit eşlem piksel verileri Native Heap'te depolanırken Java yığınında yalnızca küçük bir sarmalayıcı nesne bulunur.
Bir uygulamanın resim göstermesi gerektiğinde, resim genellikle sıkıştırılmış bir resim dosyasından Bitmap'e dönüştürülür ve yığında depolanır.
Paylaşılan bit eşlemler (ashmem/memfd)
Bir bit eşlem işlemler arasında aktarıldığında (ör. bildirim için Binder aracılığıyla SystemUI'ye), Android paylaşılan bellek (ashmem veya memfd) kullanarak piksel verilerini kopyalamaktan kaçınır.
Bir Bitmap örneği, Bitmap.asShared() çağrılarak paylaşılan belleğe açıkça veya bir Bitmap, Parcel içine yerleştirilirse (genellikle Bitmap'i Bundle gibi bir Parcelable'ye ekleyerek) örtülü olarak kopyalanabilir ve Binder IPC üzerinden gönderilebilir.
Binder IPC üzerinden paylaşılan bir Bitmap gönderildiğinde piksel verileri kopyalanmaz. Bunun yerine, paylaşılan bir bellek bölgesine referans veren bir dosya tanımlayıcısı, alıcı işleme kopyalanır. Temel bellek bölgesi birden fazla işlem arasında paylaşılabilir ve kendisine referans veren tüm dosya tanımlayıcıları kapatılana kadar boşaltılmaz.
Değişebilir ve değişmez bit eşlemler
- Değiştirilebilir Bit Eşlemler: Oluşturulduktan sonra değiştirilebilir (ör.
Canvasaracılığıyla). Her zaman kendi özel bellek ayırmalarını gerektirirler. Değiştirilebilir bir Bitmap kopyalanırsa derin kopya (tüm piksel verilerinin ikinci kopyası) oluşturulmalıdır. - Değiştirilemez Bit Eşlemler: Değiştirilemez. Bu sayede, farklı
Bitmapörnekleri arasında aynı temel bellek arabelleğini paylaşma gibi optimizasyonlar yapılabilir. APK kaynaklarından yüklenen bit eşlemler (BitmapFactory) genellikle sabittir.
Verimli bit eşlem işleme
Bit eşlem havuzu ve yeniden kullanımı
Bit eşlemlerin sık sık ayrılması ve serbest bırakılması ayrılma karmaşasına neden olur. Bu durum, çöp toplama işleminin sürekli olarak çalışmasına yol açar. Yaygın olarak kullanılan resim yükleme kitaplıkları Bitmap Pool kullanır.
Google, Java tabanlı uygulamalar için Glide'ı, Kotlin tabanlı uygulamalar için ise (özellikle Jetpack Compose kullanılırken) Coil'ı çözüm olarak önerir.
Artık ihtiyaç duyulmayan bir bit eşlem, çöp toplama işlemine tabi tutulmak yerine uygulama tarafından bitmap.recycle() çağrılarak veya bir havuza döndürülerek serbest bırakılır. Aynı boyut ve yapılandırmaya sahip bir bit eşlem bir sonraki sefer gerektiğinde havuz, yeni bir ayırmayı önleyerek mevcut arabelleği sağlar.
Donanım bit eşlemleri
Bitmap.Config.HARDWARE, piksel verilerini doğrudan grafik belleğinde (DMABuf) depolamanıza olanak tanır.
- Artıları:
- Bellek tasarrufu: Uygulama veya yerel yığını kullanmaz, GPU belleğini kullanır. Genellikle bir uygulamanın kullanıcı arayüzünde gösterilen bit eşlemlerin GPU belleğine kopyalanması gerekir. Bu nedenle, bu işlem kopyalama işlemini ve ek bellek maliyetini ortadan kaldırır.
- Performans: Veriler GPU'da olduğu için çizim son derece hızlıdır.
- Eksileri:
- Değiştirilemez: Donanım bit eşlemleri değiştirilemez.
- Geri okuma yavaş: CPU'dan piksellere erişmek (ör.
getPixel()) çok maliyetlidir. - İlişkilendirme: AHAT gibi standart araçlarda izlenmesi daha zordur (aşağıya bakın).
Uygulamalı alıştırma: Bit eşlem keşfi
Bu kavramları incelemek için BitmapLab örnek uygulamasını kullanacağız.
1. dumpsys meminfo ile ölçme
BitmapLab'i başlatın ve ALLOCATE 10MB ARGB_8888'e dokunun. Ardından şu komutu çalıştırın:
adb shell dumpsys meminfo -s com.android.bitmaplab
Modern Android sürümlerinde Native Allocations (Yerel Tahsisler) bölümünü bulun. Bunlar, bit eşlemler için genel Uygulama Özeti'nden çok daha iyi ilişkilendirme sağlar:
Native Allocations
Count Total(kB)
------ ------
Bitmap (malloced): 1 10240 # <--- 10MB Bitmap data!
Bitmap (nonmalloced): 0 0
- Bit eşlem (malloced): İşlemin yerel yığınında ayrılan bit eşlemler. Bu, Android 8.0 ve sonraki sürümlerde çoğu standart bit eşlemin bulunduğu yerdir.
- Bit eşlem (malloc'siz): Donanım Bit Eşlemleri veya Paylaşılan Bit Eşlemler (
ashmemveyamemfdaracılığıyla) gibi özel bellek kullanan bit eşlemler.
BitmapLab'de Paylaşılan Bit Eşlem ayırırsanız bu, Bitmap (nonmalloced)'ye yansıtılır:
Native Allocations
Count Total(kB)
------ ------
Bitmap (malloced): 1 10240
Bitmap (nonmalloced): 1 10240 # <--- Shared Bitmap!
Paylaşılan bit eşlemlerin izlenmesi
Bazı Android sürümlerinde ve çekirdek yapılandırmalarında dumpsys meminfo, dosya tanımlayıcıları aracılığıyla işlemin adres alanına eşlenen bit eşlemler için yüksek çözünürlüklü izleme de sağlar.
Paylaşılan bit eşlemler varsayılan olarak genel bir ad ("bit eşlem") kullanır. Ayrıntılı ilişkilendirme ve benzersiz bit eşlem izlemeyi (farklı işlemler arasında paylaşılan bit eşlemleri tanımlama) etkinleştirmek için aşağıdaki sistem özelliğini etkinleştirmeniz gerekir:
adb shell setprop debug.hwui.bitmap_ashmem_long_name true
Etkinleştirildiğinde, /proc/<pid>/smaps içindeki ashmem bölgelerinin adları daha açıklayıcı olur. meminfo bu durumdan yararlanır ve sonuçlar aşağıdaki gibi görünür:
Shared Bitmaps
Count Size(KB)
------ ------
Mapped: 1 10240
Unique: 1 10240
- Eşlenmiş: Bit eşlemle ilgili tüm bellek eşlemelerinin toplam boyutu.
- Benzersiz: Yalnızca benzersiz öğelerin dikkate alındığı bit eşlemlerin boyutu (ör. aynı temel paylaşılan bit eşlem piksel verilerinin iki veya daha fazla eşlemesi yalnızca bir kez sayılır).
2. AHAT'taki bit eşlemler
AHAT, bit eşlemler için mükemmel görselleştirme sağlar.
- BitmapLab'da birkaç bit eşlem ayırın.
-bişaretini kullanarak yığın dökümü yakalayın (yerel bit eşlem verilerini dahil etmek için):adb shell am dumpheap -b png com.android.bitmaplab /data/local/tmp/bitmaps.hprof adb pull /data/local/tmp/bitmaps.hprof . ahat bitmaps.hproflocalhost:7100simgesini açın ve kenar çubuğunda Bitmaps bağlantısını bulun veyaBitmapsınıfını arayın.AHAT, bit eşlemleri tarayıcıda oluşturarak hangi görüntülerin belleği tükettiğini belirlemeyi kolaylaştırır.

3. Perfetto'daki bitmap izleri
Perfetto, bit eşlem ayırmalarını ve sayılarını zaman içinde izleyebilir. Bu sayaçlar, belirli bir uygulama için gfx atrace kategorisi etkinleştirildiğinde Android çerçevesi tarafından yayınlanır.
İzleme başlatın.
gfxkategorisini eklemeniz ve-aişaretini kullanarak belirli bir uygulama paketini hedeflemeniz gerekir:external/perfetto/tools/record_android_trace -o bitmaps.perfetto-trace \ -t 15s -b 64mb view gfx dalvik am res memory -a com.android.bitmaplabBitmapLab'de Allocate (Ayır) ve Clear (Temizle) düğmelerine art arda dokunun.
Ayrıca Parcel/Unparcel Bitmap'e (Paketle/Paketi Aç Bit Eşlem) dokunun.
İzi ui.perfetto.dev'de analiz edin.
com.android.bitmaplab ile ilgili işlem bölümünde şunları görürsünüz:
* Bitmap Sayısı: Etkin bit eşlemlerin sayısını gösteren sayaç.
* Bit eşlem belleği: Bit eşlemler tarafından kullanılan toplam bayt sayısını gösteren sayaç.
Üst düzey dilimler (Perfetto SDK)
BitmapLab, bit eşlem işlemleri için üst düzey dilimler yaymak üzere Perfetto SDK'yı da kullanır. İzde BitmapLab_ ifadesini arayarak şunları bulabilirsiniz:
* BitmapLab_parcelUnparcel: Paketleme ve paket açma mantığını kapsayan dilimler.
* BitmapLab_postNotification: Bildirim yayınlama akışını kapsayan dilimler.
Bildirim akışlarını izleme
Bildirim Yayınla'ya dokunduğunuzda uygulama, mevcut bit eşlemi içeren bir bildirim oluşturur ve bunu sisteme gönderir. Bundan sorumlu olan çerçeve kodu, paketlemeyi (bit eşlemi Binder IPC üzerinden gönderilecek bir pakete yazma) ve paket açmayı (bit eşlemi alıcı taraftaki bir paketten okuma) bağlayan akış etkinlikleriyle Perfetto dilimleri yayar.
Aşağıdaki ekran görüntüsünde, bildirimi yayınlamak için Binder işleminde kullanılacak büyük bit eşlemi parçalara ayıran uygulama ve system_server sürecindeki ilgili parçaları birleştirme işlemi gösterilmektedir.

Perfetto'yu kullanarak, aynı bildirim bit eşlemini iş parçacıkları ve işlemler arasında daha da yayılırken takip edebilirsiniz. Örneğin, system_server içindeki bir bağlayıcı iş parçacığından (INotificationManager Binder sunucusunu uygular) aynı bit eşlemi daha sonra bildirim gölgesinde gösterilmek üzere com.android.systemui'ye iletebilecek system_server çalışan iş parçacıklarına.
Sistem uygulaması sorgulamaları
SystemUI (Bildirimler) ve Launcher gibi sistem uygulamaları benzersiz zorluklarla karşı karşıyadır:
- Sınırsız İçerik: Bildirimler ve widget'lar çok sayıda olabilir. Her biri büyük bir bit eşlem içeriyorsa sistemin belleği kısa sürede tükenebilir.
- Yineleme: Aynı uygulama simgesi, Başlatıcı'nın önbelleğinde, SystemUI'nın bildirim alanında ve Ayarlar uygulamasında tutuluyor olabilir.
- Donanım arabellekleri üzerinden paylaşım: Bunu azaltmak için sistem bileşenleri, süreçler arasında
HardwareBufferörneklerini paylaşan merkezi bir "görüntü boşaltma" hizmetine geçiş yapıyor. DMABuf ilişkilendirmesi: Donanım bit eşlemleri yığın alanından tasarruf sağlar ancak DMABuf belleğini kullanır. Bu belleği standart bellek araçlarında belirli bir işleme ilişkilendirmek daha zordur.
Sistem genelinde DMABuf ayırmalarını görmek için
adb shell dmabuf_dumpsimgesini kullanın. Bu araç, arabelleklerin süreç bazında dökümünü sağlar:droid.bitmaplab:19562 Name Rss Pss nr_procs Inode Exporter <unknown> 3840 kB 1280 kB 3 3397 virtio_gpu system 12 kB 4 kB 3 3398 system <unknown> 3840 kB 1920 kB 2 3399 virtio_gpu system 12 kB 6 kB 2 3400 system PROCESS TOTAL 11556 kB 5136 kB- RSS: İşleme eşlenmişse arabelleğin toplam boyutu.
- Pss: Orantılı boyut (RSS'nin arabelleği paylaşan işlem sayısına bölünmesi). Bu, muhasebe için en iyi metriktir.
- nr_procs: Şu anda bu arabelleğe referans tutan işlemlerin sayısı.
- Dışa aktarıcı: Arabelleği ayıran sürücü (ör.
virtio_gpuCuttlefish'te veya donanımda tedarikçiye özel bir Ion/DMA-BUF yığını).
Tüm arabelleklerin ve sistem genelinde toplam DMA-BUF kullanımının özeti için
adb shell dmabuf_dump -bkomutunu da kullanabilirsiniz.