Uygulamanızın belleğini yönetme

Bu sayfada, uygulamanızın bellek kullanımını proaktif olarak nasıl azaltabileceğiniz açıklanmaktadır. Daha fazla bilgi için belleği nasıl yönettiğini öğrenmek için bkz. Bellek yönetimine genel bakış.

Rastgele erişimli bellek (RAM), yazılım geliştirme ortamları için değerli bir kaynaktır. Fiziksel belleğin genellikle kısıtlı olduğu bir mobil işletim sistemi için daha da değerlidir. Hem Android Runtime (ART) hem de Dalvik sanal makinesi, rutin atıklar gerçekleştirse de bu, uygulamanızın belleği ne zaman ve nerede ayırıp serbest bıraktığını göz ardı edebileceğiniz anlamına gelmez. Yine de, genellikle nesnede tutunmasından kaynaklanan bellek sızıntıları oluşturmaktan kaçınmanız gerekir. referansları varsa ve mevcut tüm öğeleri Reference nesne doğru zamanı ifade eder.

Kullanılabilir bellek ve bellek kullanımını izleme

Uygulamanızın bellek kullanımıyla ilgili sorunlarını düzeltmeden önce bu sorunları bulmanız gerekir. İlgili içeriği oluşturmak için kullanılan Android Studio'daki Bellek Profil Aracı, ve hafıza sorunlarını aşağıdaki şekillerde teşhis edebilirsiniz:

  • Uygulamanızın zaman içinde nasıl bellek ayırdığını görün. Memory Profiler'da, öğelerin gerçek zamanlı olarak uygulamanızın kullandığı bellek miktarı, ayrılan Java nesnelerinin sayısı ve atık toplama zamanı gerçekleşir.
  • Uygulamanız çalışırken çöp toplama etkinlikleri başlatın ve Java yığınının anlık görüntüsünü alın koşar.
  • Uygulamanızın bellek ayırmalarını kaydedin, ayrılan tüm nesneleri inceleyin, her ayırma için yığın izlemeyi görüntüleyin ve Android Studio düzenleyicisinde ilgili koda atlayın.

Olaylara yanıt olarak bellek salma

Android, Bellek yönetimine genel bakış bölümünde açıklandığı gibi, kritik görevler için bellek boşaltmak amacıyla uygulamanızdan bellek geri alabilir veya gerekirse uygulamanızı tamamen durdurabilir. Sistem belleğini dengelemeye daha fazla yardımcı olmak ve sistemin uygulama işleminizi durdurması gerekmesini önlemek için Activity sınıflarınıza ComponentCallbacks2 arayüzünü uygulayabilirsiniz. Sağlanan onTrimMemory(). geri çağırma yöntemi, uygulamanızı yaşam döngüsü veya bellekle ilgili, iyi bir performans gösteren gönüllü olarak bellek kullanımını azaltması için bir fırsattır. Bellek boşaltmak, uygulamanızın bellek azlığı nedeniyle kapatılma olasılığını azaltabilir.

Bellekle ilgili farklı değişikliklere yanıt vermek için onTrimMemory() geri çağırmasını uygulayabilirsiniz. etkinlikleri için aşağıdaki örnekte gösterildiği gibi:

Kotlin

import android.content.ComponentCallbacks2
// Other import statements.

class MainActivity : AppCompatActivity(), ComponentCallbacks2 {

    // Other activity code.

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that is raised.
     */
    override fun onTrimMemory(level: Int) {

        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }

        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

Java

import android.content.ComponentCallbacks2;
// Other import statements.

public class MainActivity extends AppCompatActivity
    implements ComponentCallbacks2 {

    // Other activity code.

    /**
     * Release memory when the UI becomes hidden or when system resources become low.
     * @param level the memory-related event that is raised.
     */
    public void onTrimMemory(int level) {

        if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
            // Release memory related to UI elements, such as bitmap caches.
        }

        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            // Release memory related to background processing, such as by
            // closing a database connection.
        }
    }
}

Ne kadar belleğe ihtiyacınız olduğunu kontrol etme

Android, çalışan birden fazla işleme izin vermek için her işleme ayrılan yığın boyutuyla ilgili kesin bir sınır belirler. uygulamasını indirin. Tam yığın boyutu sınırı, cihazın ne kadar RAM'e sahip olduğuna bağlı olarak cihazlar arasında değişir. yardımcı olabilir. Uygulamanız yığın kapasitesine ulaşır ve daha fazla bellek tahsis etmeye çalışırsa sistem OutOfMemoryError.

Bellek yetersizliğini önlemek amacıyla, sisteme sorgu göndererek ne kadar yığın alanının geçerli cihazda kullanılabilir. Şu numarayı arayarak sisteme bu rakam için sorgu gönderebilirsiniz: getMemoryInfo() Bu işlev, cihazın mevcut bellek durumu hakkında bilgi sağlayan bir ActivityManager.MemoryInfo nesnesi döndürür. Bu bilgiler arasında kullanılabilir bellek, toplam bellek ve bellek eşiği (sistemin işlemleri durdurmaya başladığı bellek seviyesi) yer alır. ActivityManager.MemoryInfo nesnesi, lowMemory, Bu, cihazın belleğinin azalıp kalmadığını gösteren basit bir boole değeridir.

Aşağıdaki örnek kod snippet'inde, getMemoryInfo() yönteminin uygulamanızda nasıl kullanılacağı gösterilmektedir.

Kotlin

fun doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    if (!getAvailableMemory().lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private fun getAvailableMemory(): ActivityManager.MemoryInfo {
    val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    return ActivityManager.MemoryInfo().also { memoryInfo ->
        activityManager.getMemoryInfo(memoryInfo)
    }
}

Java

public void doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();

    if (!memoryInfo.lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private ActivityManager.MemoryInfo getAvailableMemory() {
    ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);
    return memoryInfo;
}

Daha fazla bellek tasarrufu sağlayan kod yapıları kullanın

Bazı Android özellikleri, Java sınıfları ve kod yapıları, diğerlerinden daha fazla bellek kullanır. Şunları yapabilirsiniz: kodunuzda daha verimli alternatifler seçerek uygulamanızın kullandığı bellek miktarını en aza indirin.

Hizmetleri dikkatli kullanın

Gereksiz durumlarda hizmetleri çalışır durumda bırakmamanızı önemle tavsiye ederiz. Gereksiz hizmetleri çalışır durumda bırakmak, bir Android uygulamasının yapabileceği en kötü bellek yönetimi hatalarından biridir. Uygulamanız arka planda çalışması için bir hizmete ihtiyaç duyuyorsa bir iş çıkarması gerekmediği sürece çalışır. Görevini tamamladığında hizmetinizi durdurun. Aksi halde bellek sızıntısına neden olabilirsiniz.

Bir hizmeti başlattığınızda sistem, ilgili hizmetin sürecini çalışmaya devam ettirmeyi tercih eder. Bu davranışı nedeniyle hizmet işlemleri çok pahalıya mal olur, çünkü hizmet tarafından kullanılan RAM diğer işlemler için kullanılamaz. Bu, sistemin LRU önbelleği içinde saklayabileceği önbelleğe alınmış işlemlerin sayısını azaltır ve uygulama geçişini daha az verimli hale getirir. Bellek yetersiz olduğunda ve sistem, çalışan tüm hizmetleri barındıracak kadar işlem sürdüremediğinde sistemde aşırı işleme yol açabilir.

Genellikle, kullanılabilir hizmetlere ilişkin sürekli talepler nedeniyle kalıcı hizmetlerden kaçının hafızada bulabilirsiniz. Bunun yerine WorkManager gibi alternatif bir uygulama kullanmanızı öneririz. Okuyucu Gelirleri Yöneticisi'ni arka plan işlemlerini programlamak için WorkManager yönteminin nasıl kullanılacağı hakkında bilgi için bkz. Sürekli çalışma.

Optimize edilmiş veri kapsayıcıları kullanma

Programlama dili tarafından sağlanan sınıflardan bazıları mobil cihazlarda kullanım için optimize edilmemiştir. Örneğin, HashMap uygulaması bellek olabilir verimsizdir. Çünkü her eşleme için ayrı bir giriş nesnesine ihtiyaç duyar.

Android çerçevesi, SparseArray, SparseBooleanArray ve LongSparseArray gibi çeşitli optimize edilmiş veri kapsayıcıları içerir. Örneğin, SparseArray sınıfları, sistemin anahtarı ve bazen değeri otomatik kutuya koyma ihtiyacını ortadan kaldırdığı için daha verimlidir. Bu işlem, giriş başına bir veya iki nesne daha oluşturur.

Gerekirse, sade bir veri yapısı için dilediğiniz zaman ham dizilere geçebilirsiniz.

Kod soyutlamalarında dikkatli olun

Geliştiriciler, kod esnekliğini ve bakımını iyileştirebildiğinden genellikle soyutlamalardan iyi bir programlama uygulaması olarak yararlanır. Ancak soyutlamalar, genellikle çalıştırılması gereken daha fazla kod gerektirdiğinden ve kodu belleğe eşlemek için daha fazla zaman ve RAM gerektirdiğinden çok daha maliyetlidir. Soyutlamalarınız önemli ölçüde faydalı değilse bunlardan kaçının.

Serileştirilmiş veriler için basit protobuf'ları kullan

Protokol arabellekleri (protobuf'ler), Google tarafından yapılandırılmış verileri serileştirmek için tasarlanmış, dile ve platforma duyarlı olmayan, genişletilebilir bir mekanizmadır. XML'ye benzer ancak daha küçük, daha hızlı ve daha basittir. Verileriniz için protobuf kullanıyorsanız istemci tarafı kodunuzda her zaman hafif protobuf'leri kullanın. Normal protobuf'ler son derece ayrıntılı kodlar oluşturur. Bu kodlar, uygulamanızda RAM kullanımının artması, APK boyutunun önemli ölçüde artması ve yürütmenin yavaşlaması gibi birçok soruna neden olabilir.

Daha fazla bilgi için protobuf readme dosyasını inceleyin.

Bellek karmaşıklığından kaçının

Çöp toplama etkinlikleri uygulamanızın performansını etkilemez. Ancak birçok çöp toplama işlemi kısa bir süre içinde meydana gelen olaylar da pilin hızlı bir şekilde tükenmesine neden olabileceği gibi, marjinal şekilde de çöp toplayıcı ile arasındaki gerekli etkileşimler nedeniyle kare oluşturma süresini uzatır uygulama iş parçacıklarıdır. Sistem ne kadar fazla çöp toplarsa pil o kadar hızlı tükenir.

Bellek karması genellikle çok sayıda atık toplama etkinliğinin oluşmasına neden olabilir. İçinde alıştırma olarak bilinen bellek karmaşası, belirli bir süre tahminidir.

Örneğin, bir for döngüsü içinde birden fazla geçici nesne ayırabilirsiniz. Dilerseniz bir görünümün onDraw() işlevi içinde yeni Paint veya Bitmap nesneleri de oluşturabilirsiniz. Her iki durumda da uygulama, çok sayıda nesneyi yüksek ses seviyesinde hızlı bir şekilde oluşturur. Bu Üretken yapay zeka, genç nesilde mevcut tüm belleği hızla tüketerek atık toplama işlemini zorunlu kılar. gerçekleşeceği tahmin edilen iyileşmeleri görebilirsiniz.

Şuradaki yerleri bulmak için Bellek Profil Aracı'nı kullanın: bu sorunları düzeltmeden önce bellek karmaşasının yüksek olduğu bir kod görüntülersiniz.

Kodunuzdaki sorunlu alanları belirledikten sonra, bu alandaki ayırma sayısını azaltmaya çalışın kritik önemdeki alanlar var. Öğeleri iç döngülerden veya fabrikaya dayalı bir ayırma yapısına taşımayı düşünebilirsiniz.

Nesne havuzlarının kullanım alanına fayda sağlayıp sağlamadığını da değerlendirebilirsiniz. Nesne havuzu kullanırken, artık gerekli olmayan bir nesne örneğini yere bırakmak yerine havuza bırakırsınız. Bu tür bir nesne örneği tekrar gerektiğinde bu örnek yerine havuzdan en iyi uygulamaları paylaşacağım.

Bir nesne havuzunun belirli bir durumda uygun olup olmadığını belirlemek için performansı ayrıntılı olarak değerlendirin. Nesne havuzlarının performansı düşürebileceği durumlar vardır. Havuzlar, tahsislerden kaçınmasına rağmen başka ek maliyetler getirir. Örneğin, havuz bakımı genellikle senkronizasyonuna yardımcı olur. Ayrıca, serbest bırakma sırasında bellek sızıntılarını önlemek için havuzlanmış nesne örneğini temizlemek ve ardından edinme sırasında bu örneğin başlatılması sıfır olmayan bir yükü beraberinde getirebilir.

Havuzda gerekenden daha fazla nesne örneğinin saklanması da çöpe yük oluşturur koleksiyonudur. Nesne havuzları, çöp toplama çağrılarının sayısını azaltsa da etkin (erişilebilir) bayt sayısıyla orantılı olduğu için her çağrı için gereken çalışma miktarını artırır.

Yoğun bellek kullanan kaynakları ve kitaplıkları kaldırma

Kodunuzdaki bazı kaynaklar ve kitaplıklar, farkında olmadan bellek tüketebilir. Üçüncü taraf kitaplıklar veya yerleştirilmiş kaynaklar dahil olmak üzere uygulamanızın genel boyutu, uygulamanızın ne kadar bellek kullanacağını etkileyebilir. Gereksiz etiketleri kaldırarak uygulamanızın bellek tüketimini iyileştirebilirsiniz ya da olması gerekenden daha fazla olması gereken bileşenleri ya da kaynakları ve kitaplıkları içerebilir.

Genel APK boyutunu küçültme

Uygulamanızın genel boyutunu küçülterek uygulamanızın bellek kullanımını önemli ölçüde azaltabilirsiniz. Bit eşlem boyutu, kaynaklar, animasyon çerçeveleri ve üçüncü taraf kitaplıkların tümü en iyi yoludur. Android Studio ve Android SDK, uygulamanızın boyutunu küçültmeye yardımcı olacak kaynaklar ve dış bağımlılıklar hakkında bilgi edindiniz. Bu araçlar, RACI matrisleri gibi modern kod küçültme yöntemlerini destekler: R8 derlemesi.

Uygulamanızın genel boyutunu küçültme hakkında daha fazla bilgi için bkz. Uygulamanızın boyutunu küçültün.

Bağımlılık ekleme için Hilt veya Dagger 2'yi kullanma

Bağımlılık ekleme çerçeveleri, yazdığınız kodu basitleştirebilir ve test ve diğer yapılandırma değişiklikleri için yararlı olan uyarlanabilir bir ortam sağlayabilir.

Uygulamanızda bağımlılık ekleme çerçevesi kullanmayı düşünüyorsanız Hilt veya Dagger'ı kullanmayı düşünebilirsiniz. Hilt, bir bağımlılık yerleştirmedir geliştirmeyi öğreneceksiniz. Dagger, uygulamanızın özelliklerini taramak için yansıma girin. Dagger'ın statik derleme zamanı uygulamasını, gereksiz çalışma zamanı maliyeti veya bellek kullanımı olmadan Android uygulamalarında kullanabilirsiniz.

Yansıtma kullanan diğer bağımlılık ekleme çerçeveleri, kodunuzu ek açıklamalar için tarayarak işlemleri başlatır. Bu işlem çok daha fazla CPU döngüsü ve RAM gerektirebilir ve uygulama başlatıldığında belirgin bir gecikmeye neden olabilir.

Harici kitaplıklar kullanma konusunda dikkatli olun

Harici kitaplık kodu genellikle mobil ortamlar için yazılmaz ve mobil istemcide çalışmak için verimsiz olabilir. Harici bir kitaplık kullandığınızda bu kitaplığı optimize etmeniz gerekebilir mobil cihaz kitaplığı. Bu çalışmayı önceden planlayın ve kitaplığı kullanmadan önce kod boyutu ve RAM kullanımı açısından analiz edin.

Mobil cihazlar için optimize edilmiş bazı kitaplıklar bile farklı uygulamalar nedeniyle sorunlara neden olabilir. Örneğin, bir kitaplık hafif protobuf'ler kullanırken başka bir kitaplık mikro protobuf'ler kullanabilir. Bu da uygulamanızda iki farklı protobuf uygulamasına neden olur. Bu durum, günlük kaydı, analizler, resim yükleme çerçeveleri, önbelleğe alma ve beklemediğiniz diğer birçok şeyin farklı uygulamalarında da görülebilir.

ProGuard, doğru işaretlerle API'leri ve kaynakları kaldırmanıza yardımcı olsa da kitaplığın büyük dahili bağımlılıklarını kaldıramaz. Bu kitaplıklarda istediğiniz özellikler daha düşük düzeyde bağımlılıklar gerektirebilir. Bu durum, özellikle kitaplıklarda yansıma kullanıldığında (yaygın bir durumdur ve ProGuard'ın çalışması için manuel olarak ayarlanması gerekir) kitaplıktan bir Activity alt sınıfı kullandığınızda (çok sayıda bağımlılığa sahip olabilir) sorunlu hale gelir.

Onlarca özellik arasından yalnızca bir veya iki özellik için paylaşılan kitaplık kullanmaktan kaçının. Kullanmadığınız çok fazla kod ve ek yük eklemeyin. Bir kitaplığı kullanıp kullanmayacağınıza karar verirken bir uygulamaya ne dersiniz? Aksi takdirde, dilerseniz bazı ipuçları vereceğim.