美文网首页
WebView打开慢、卡问题跟踪

WebView打开慢、卡问题跟踪

作者: From64KB | 来源:发表于2024-06-05 14:36 被阅读0次

测试手机型号:Oppo K9 5G CPU:高通768G 内存:8G

首先看一个Perfetto图,看看为什么打开Web页面这样的卡和慢:

首次打开
Release版本的APK,首次打开WebView在onCreate创建WebView时耗时243.5ms。再次打开WebView页面耗时降到了6.4ms:
再次打开

由此可见首次打开WebView初始化会花费大量的时间。

接着需要看下具体是哪些方法调用花费了这么多时间:

  1. WebViewChromium.init 中的WebViewChromiumFactoryProviders.startYourEngines
  2. WebViewChromium.initForReal
    其中方法1在首次打开页面后不再出现,2再次初始化时间从44.6ms缩短到6.4ms。

这里就产生了一种优化思路,在进程空闲并且预期可以打开Web的页面,可以预先初始化这些组件,那么后续打开的用户体验就会好很多。

顺着这个思路,网上有很多方案,例如提前反射调用WebViewChromiumFactoryProviders.startYourEngines。这种想法很好,但是实践过程中发现并没有什么作用。将反射出来的类及其父类中的declaredMethods都打印出来,发现找不到相应的startYourEngines方法。

 E  [main] search in parent:class com.android.webview.chromium.WebViewChromiumFactoryProvider
 E  [main] android.content.Context
 E  [main] method in parent:b,kotlin.Unit,1
 E  [main] android.webkit.WebViewDelegate
 E  [main] method in parent:create,kotlin.Unit,1
 E  [main] java.io.File
 E  [main] method in parent:d,kotlin.Unit,1
 E  [main] method in parent:h,kotlin.Unit,0
 E  [main] android.content.Context
 E  [main] method in parent:l,kotlin.Unit,1
 E  [main] method in parent:preloadInZygote,kotlin.Unit,0
 E  [main] method in parent:setWebLayerRunningInSameProcess,kotlin.Unit,0
 E  [main] java.lang.Runnable
 E  [main] method in parent:a,kotlin.Unit,1
 E  [main] android.content.Context
 E  [main] method in parent:addWebViewAssetPath,kotlin.Unit,1
 E  [main] org.chromium.android_webview.AwSettings
 E  [main] method in parent:c,kotlin.Unit,1
 E  [main] method in parent:createPacProcessor,kotlin.Unit,0
 E  [main] android.webkit.WebView
 E  [main] android.webkit.WebView$PrivateAccess
 E  [main] method in parent:createWebView,kotlin.Unit,2
 E  [main] android.content.pm.PackageInfo
 E  [main] method in parent:e,kotlin.Unit,1
 E  [main] method in parent:f,kotlin.Unit,0
 E  [main] method in parent:g,kotlin.Unit,0
 E  [main] method in parent:getCookieManager,kotlin.Unit,0
 E  [main] method in parent:getGeolocationPermissions,kotlin.Unit,0
 E  [main] method in parent:getPacProcessor,kotlin.Unit,0
 E  [main] method in parent:getServiceWorkerController,kotlin.Unit,0
 E  [main] method in parent:getStatics,kotlin.Unit,0
 E  [main] method in parent:getTokenBindingService,kotlin.Unit,0
 E  [main] method in parent:getTracingController,kotlin.Unit,0
 E  [main] method in parent:getWebIconDatabase,kotlin.Unit,0
 E  [main] method in parent:getWebStorage,kotlin.Unit,0
 E  [main] method in parent:getWebViewClassLoader,kotlin.Unit,0
 E  [main] android.content.Context
 E  [main] method in parent:getWebViewDatabase,kotlin.Unit,1
 E  [main] method in parent:i,kotlin.Unit,0
 E  [main] java.util.concurrent.Callable
 E  [main] method in parent:j,kotlin.Unit,1
 E  [main] java.lang.Runnable
 E  [main] method in parent:k,kotlin.Unit,1
 E  [main] method in parent:m,kotlin.Unit,0
 E  [main] boolean
 E  [main] method in parent:n,kotlin.Unit,1

查看Chromium中的WebViewChromiumFactoryProviders源码,确实是有这个方法的。

startYourEngines方法.png

那么不难得出这个方法被混淆了,无法通过反射访问了。由于这个类是Android系统提供的,对此应用端无法keep。因此提前反射调用WebViewChromiumFactoryProviders.startYourEngines 在实际运行中是无效的,后续的Prefetto图也证明了这个结论。
至于WebViewChromium.initForReal初始化逻辑就更加复杂了,通过反射也很难完成相应的初始化。

如果是直接在进程创建的时候新建一个WebView呢?

var webView: WebView? = WebView(app)
webView = null

这样对于上述情况是有改善的,那是否会造成内存占用方面的影响呢?看数据:

  1. 未初始化WebView占用
Applications Memory Usage (in Kilobytes):
Uptime: 168160548 Realtime: 812073693

** MEMINFO in pid 16882 [com.xxxx.xxxx:web] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
  Native Heap     5945     5912        0       21     7328    18432    13427     5004
  Dalvik Heap     8088     3140     4636       20     9804     5707     4281     1426
 Dalvik Other     3694     3616       32        2     4444                           
        Stack     1564     1564        0        0     1572                           
       Ashmem        7        0        0        0      392                           
    Other dev       12        0       12        0      416                           
     .so mmap     2328      392      104        6    25612                           
    .jar mmap      715        0        0        0    29232                           
    .apk mmap     3803      312        0        0    12136                           
    .dex mmap    14265       48      840        0    40488                           
    .oat mmap      175        0        0        0    13212                           
    .art mmap     2096      776      768       98    13508                           
   Other mmap      449       40       64        0     2176                           
      Unknown      920      912        0        2     1380                           
        TOTAL    44210    16712     6456      149   161700    24139    17708     6430
 
 App Summary
                       Pss(KB)                        Rss(KB)
                        ------                         ------
           Java Heap:     4684                          23312
         Native Heap:     5912                           7328
                Code:     1696                         120772
               Stack:     1564                           1572
            Graphics:        0                              0
       Private Other:     9312
              System:    21042
             Unknown:                                    8716
 
           TOTAL PSS:    44210            TOTAL RSS:   161700       TOTAL SWAP PSS:      149
 
 Objects
               Views:        0         ViewRootImpl:        0
         AppContexts:        3           Activities:        0
              Assets:       29        AssetManagers:        0
       Local Binders:       24        Proxy Binders:       42
       Parcel memory:       12         Parcel count:       48
    Death Recipients:        1      OpenSSL Sockets:        1
            WebViews:        0
 
 SQL
         MEMORY_USED:       81
  PAGECACHE_OVERFLOW:       14          MALLOC_SIZE:       46
  1. 进程启动即初始化WebView占用
Applications Memory Usage (in Kilobytes):
Uptime: 168379408 Realtime: 812292552

** MEMINFO in pid 18341 [com.xxxx.xxxx:web] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
  Native Heap     7239     7212        0       19     8616    18432    15300     3131
  Dalvik Heap     8591     3676     4596       19    10312     6204     4653     1551
 Dalvik Other     4013     3908       32        2     4788                           
        Stack     1808     1808        0        0     1816                           
       Ashmem      162      156        0        0      556                           
    Other dev        8        0        8        0      412                           
     .so mmap     3492      420      468        5    27436                           
    .jar mmap      907        0       48        0    30256                           
    .apk mmap    15448      312    12260        0    22608                           
    .dex mmap    24667       48     6904        0    45220                           
    .oat mmap      210        0        0        0    14148                           
    .art mmap     2349      900      784       80    14064                           
   Other mmap     1673       40     1336        0     3212                           
      Unknown     2317     2312        0        1     2776                           
        TOTAL    73010    20792    26436      126   186220    24636    19953     4682
 
 App Summary
                       Pss(KB)                        Rss(KB)
                        ------                         ------
           Java Heap:     5360                          24376
         Native Heap:     7212                           8616
                Code:    20460                         139816
               Stack:     1808                           1816
            Graphics:        0                              0
       Private Other:    12388
              System:    25782
             Unknown:                                   11596
 
           TOTAL PSS:    73010            TOTAL RSS:   186220       TOTAL SWAP PSS:      126
 
 Objects
               Views:        0         ViewRootImpl:        0
         AppContexts:        4           Activities:        0
              Assets:       32        AssetManagers:        0
       Local Binders:       42        Proxy Binders:       44
       Parcel memory:       15         Parcel count:       60
    Death Recipients:        3      OpenSSL Sockets:        1
            WebViews:        0
 
 SQL
         MEMORY_USED:       81
  PAGECACHE_OVERFLOW:       14          MALLOC_SIZE:       46

简单对比下:

未初始化WebView 初始化WebView 差异MB
PSS 44210 73010 增加28.125MB
RSS 161700 186220 增加23.95MB

这里讲了内存开销,那收益是什么样的呢?

收益.png
WebView创建时间下降到了17.9ms。将进程初始化的Perfetto打印出来:
初始化.png
可以看到,bindApplicationWebViewChromium新建花费的时间是882.4ms。

可见提前初始化WebView对提高首次WebView打开速度确实有帮助,但是会产生30MB左右的内存开销(不同机型可能不太一致)。
后续采取的策略是在可能会打开WebView的场景,首先打开Web进程,并根据下发配置来确定是否在进程起来的时候初始化一个WebView。

相关文章

网友评论

      本文标题:WebView打开慢、卡问题跟踪

      本文链接:https://www.haomeiwen.com/subject/nzeuqjtx.html