WebView ve bellek

WebView, Android uygulamanızda web içeriği görüntülemenize olanak tanıyan güçlü bir bileşendir. Ancak temelde tam özellikli bir tarayıcı motoru (Chromium) olduğundan önemli bir bellekte kaplanan yer ve karmaşık bir çoklu işlem mimarisine sahiptir.

Teknik arka plan: Çok süreçli mimari

WebView, modern Android destekli cihazlarda güvenliği ve kararlılığı artırmak için çok işlemli bir model kullanır. Uygulamanız bir WebView kullandığında bellek farklı işlemler arasında dağıtılır:

  1. Tarayıcı süreci (uygulama süreci): Bu, uygulamanızın ana sürecidir. Java WebView nesnesini ve Chromium motorunun "tarayıcı" bölümünü içerir. Bu işlem; kullanıcı arayüzünü, ağ isteklerini ve GPU oluşturmayı (doğrudan Android HWUI oluşturma ardışık düzenine entegre edilmiştir) yönetir. Chrome'un aksine WebView'da ayrı bir GPU işlemi yoktur.
  2. Oluşturucu süreci: Bu süreç, HTML'yi ayrıştırmaktan, JavaScript'i çalıştırmaktan ve düzen oluşturmaktan sorumludur. Güvenlik nedeniyle sistemin geri kalanından izole edilmiştir. Şu anda uygulamalar, Chrome'un farklı siteler için genellikle ayrı oluşturucu işlemleri kullanmasının aksine, tüm WebView'lar için yalnızca bir oluşturucu işlemi almaktadır (birkaç nadir özel durum hariç).

WebView Mimarisi

Bu neden önemli?

dumpsys meminfo <your_package> kullandığınızda yalnızca tarayıcı süreci (uygulama süreciniz) tarafından kullanılan bellek gösterilir. Oluşturma işlemi tarafından kullanılan bellek ayrı olarak hesaplanır.

Tarayıcı işlemi içinde WebView belleği şu şekilde dağıtılır:

  • Java yığını: WebView Java sarmalayıcısını ve ilgili nesneleri içerir.
  • Yerel yığın: Chromium tarayıcı motorunun dahili veri yapılarını, önbelleklerini ve durumunu içerir. PartitionAlloc kullanımı nedeniyle bazı WebView yerel ayırmalarının dumpsys meminfo içindeki "Yerel yığın" altında sayılmayabileceğini ve bunun yerine "Diğer" veya "Bilinmiyor" altında görünebileceğini unutmayın.
  • Paylaşılan bellek: Grafik arabelleklerini ve diğer verileri paylaşmak için kullanılır. Bu, dumpsys meminfo tarafından net bir şekilde kategorize edilmemiş olabilir.

Sorun giderme araçları

Chrome Geliştirici Araçları

WebView'daki (oluşturucu işlemi) belleği analiz etmek için en güçlü araç Chrome Geliştirici Araçları'dır.

  1. Uygulamanızda WebView hata ayıklamayı etkinleştirin:

    // NOTE: In production, this should be gated behind a developer setting
    // or only enabled for debuggable builds to prevent reverse engineering.
    WebView.setWebContentsDebuggingEnabled(true);
    
  2. Cihazınızı USB ile bağlayın.

  3. Ana makinenizde Chrome'u açın ve chrome://inspect/#devices adresine gidin.

  4. Uygulamanızı bulup incele'yi tıklayın.

  5. Yığın anlık görüntüleri almak veya JavaScript yığını için tahsis zaman çizelgelerini kaydetmek üzere DevTools penceresinde Bellek sekmesine gidin.

dumpsys meminfo

Bellek dökümünü görmek için adb shell dumpsys meminfo --all <package> simgesini kullanın. Çıkışta WebView kategorisini ve nesne sayılarını bulun.

Oluşturucuda profil oluşturma

Oluşturucu ayrı bir süreçte çalıştığından, yalnızca uygulamanızın profilini oluşturarak yerel yığın profilini oluşturamazsınız. Oluşturucu sürecinin PID'sini özellikle tanımlamanız gerekir.

Birden fazla WebView etkin olduğunda doğru oluşturucu PID'sini belirlemek için:

  1. dumpsys activity kullanımı:

    adb shell dumpsys activity processes <your_package_name>
    

    mConnections bölümünü bulun. ConnectionRecord uygulamanızı SandboxedProcessService ile bağladığınızı gösteren bir mesaj görürsünüz. Bu sürecin PID'si, oluşturucunuzdur. Örnek:

    mConnections:
      - ConnectionRecord{... com.android.memorylab/org.chromium.content.app.SandboxedProcessService0:0 ...}
    
  2. İşlem Adlarını Kontrol Edin: Oluşturucu işlemlerine genellikle com.google.android.webview:sandboxed_processX veya benzeri bir ad verilir. WebView'u yalnızca bir uygulama kullanıyorsa büyük olasılıkla tek bir WebView olacaktır.

PID'yi aldıktan sonra heapprofd kullanarak profillendirebilirsiniz.

WebView belleği için en iyi uygulamalar

Açıkça imha

Uygulamaların, bir örnekle işleri bittiğinde WebView.destroy() işlevini çağırması beklenir.

WebView, örneklerin çöp toplama işlemine tabi tutulabilmesini ve tüm kaynaklarını otomatik olarak serbest bırakabilmesini sağlamaya çalışsa da bu durumun% 100 garanti edilmesi zordur. Otomatik çöp toplama işlemi çalışsa bile önemli ölçüde gecikebilir ve uygulamanın kaynakları beklenenden çok daha uzun süre tutmasına neden olabilir.

Bir uygulama, WebView.destroy() işlevini uygun zamanda (ör. Activity.onDestroy() içinde) çağırırsa WebView nesnesinin kendisine yönelik bir referansı tutmak önemli yerel kaynakların sızmasına neden olmaz. Etkinlik alanı çöp toplama işlemine tabi tutulduğunda temizleneceğinden, WebView nesnesi yok edildikten sonra Etkinlik alanlarındaki referansların boş değerle değiştirilmesi kesinlikle gerekli değildir.

Alıştırmalar: WebView belleğiyle uygulamalı alıştırma

Alıştırma 1: Çoklu işlem ayak izini gözlemleme

  1. MemoryLab'i başlatın ve uygulamanızın belleğiyle ilgili temel bir ölçüm yapın:

    adb shell dumpsys meminfo com.android.memorylab
    

    Örnek referans değeri (aralık): TOTAL PSS: 18915 KB

  2. WebView'i başlat (Normal)'a dokunun.

  3. WebView'da Allocate JS Memory (1000 DIVs) seçeneğine birkaç kez dokunun.

  4. Uygulamanın belleğini tekrar kontrol edin:

    adb shell dumpsys meminfo com.android.memorylab
    
  5. Uygulama sürecinizdeki belleğin, temel değerle karşılaştırıldığında önemli ölçüde artmadığını gözlemleyin. Bunun nedeni, DOM öğelerinin oluşturucu işleminde olmasıdır.

  6. Oluşturucu işlemini bulun:

    adb shell ps -A | grep webview | grep sandboxed
    

    Örnek çıkış:

    u0_i9002     14227  1087    1632732 135880 do_epoll_wait       0 S com.google.android.webview:sandboxed_process0
    
  7. Oluşturucu işleminin belleğini kontrol edin (PID'sini kullanarak):

    adb shell dumpsys meminfo 14227
    
  8. Oluşturucu işleminin yüksek TOPLAM PSS'sini gözlemleyin. Örnek çalıştırmamızda, birkaç tahsis işleminden sonra ~55 MB'a çıktı. JavaScript ayırmalarının (V8 motoru tarafından işlenir) genellikle Dalvik Heap yerine dumpsys meminfo'ın Private Other veya Unknown (mmap) bölümlerine katkıda bulunduğunu unutmayın.

2. alıştırma: Java tarafındaki WebView sızıntısı

Sık yapılan bir hata, statik bir alanda veya sızıntıya neden olan uzun ömürlü bir nesnede WebView örneğini tutmaktır. WebView nesnesi, yerel kaynakları ve muhtemelen tüm oluşturucu süreçlerini tutan ağır bir "çapa" olduğundan, bu nesnenin sızdırılması çok maliyetlidir.

WebView Sızıntısının Etkisi

  1. MemoryLab'de Launch WebView (Java Leak)'e (WebView'i başlat (Java sızıntısı)) dokunun.
  2. Sayfa yüklendikten sonra etkinlik otomatik olarak kapanır (tekrarlanan gezinme ve sızıntı birikimi simülasyonu).
  3. Düğmeye 4 kez dokunun.
  4. Uygulamanızdaki WebView örneklerinin sayısını kontrol edin:

    adb shell dumpsys meminfo com.android.memorylab
    

    En alttaki Nesneler bölümünü bulun. WebViews için sayının 4'e yükseldiğini görürsünüz.

    rango'daki örnek çıkış (4 sızdırılmış örnek):

     Objects
               Views:       51         ViewRootImpl:        5
         AppContexts:       14           Activities:        5
              Assets:       38        AssetManagers:        0
       Local Binders:       55        Proxy Binders:       77
       Parcel memory:       41         Parcel count:       68
    Death Recipients:        3             WebViews:        4
    
  5. Yığın dökümü yakalayın ve sızıntıyı bulmak için AHAT'ı kullanın. Yolunuzda ahat yoksa Android ağacından oluşturabilirsiniz:

    # Dump heap from device
    adb shell am dumpheap com.android.memorylab /data/local/tmp/heap.hprof
    adb pull /data/local/tmp/heap.hprof
    # Run ahat using the built JAR (found in out/host/linux-x86/framework/)
    java -jar out/host/linux-x86/framework/ahat.jar -p 8888 heap.hprof
    
  6. AHAT web arayüzünde (localhost:8888) genel bellek kullanımını görmek için üst menüdeki allocations (tahsisler) bağlantısını (veya sites (siteler)) tıklayın.

    AHAT tahsisleri

  7. android.webkit.WebView sınıfını arayın. Tüm canlı örnekleri görmek için örnek sayısını tıklayın. Listede birden fazla örnek görürsünüz.

    AHAT WebView Instances

  8. Sızdırılan WebView örneklerinden birini tıklayın. GC kökünden örnek yol bölümüne ilerleyin. Bu öğenin sLeakedWebViews listesinde com.android.memorylab.WebViewActivity tarafından tutulduğunu görürsünüz.

    AHAT Path to GC Root


← Doğal | ↑ Yukarı | Uygulama kodu →