成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

得物App白屏優(yōu)化系列|圖片庫篇

開發(fā) 架構
本文簡要介紹了在白屏監(jiān)控能力建設過程中,圖片庫在編解碼流程、緩存讀取策略、視圖渲染加載等階段所做的一些優(yōu)化。

一、背景

圖片加載作為重中之重的App體驗指標,端側的白屏問題則是其中最為嚴重的問題之一。想象一下如果你在瀏覽交易商品、社區(qū)帖子等核心場景下,圖片無法完成加載是多么糟糕的體驗,線上過往也陸續(xù)有一些白屏的用戶反饋。 

客戶端架構側從用戶白屏問題反饋出發(fā),深入分析每一個用戶的實際情況,從0到1完成了白屏體系監(jiān)控建設,借助獨立搭建的白屏分析平臺能力,從圖片庫、網(wǎng)絡庫、CDN質(zhì)量等3個維度進行了專項治理優(yōu)化。本文重點帶你了解得物圖片庫是如何完成白屏精細化監(jiān)控的基礎能力、問題定位、治理優(yōu)化,實現(xiàn)線上用戶白屏問圖片庫相關Issue反饋基本清零。

二、白屏監(jiān)控體系

眾所周知,圖片加載全鏈路是橫跨圖片庫、網(wǎng)絡庫、多云CDN質(zhì)量等核心基建的長鏈路過程。故白屏監(jiān)控體系建設也是基于以上3個維度進行同步展開,實現(xiàn)白屏各類歸因問題的點對點跟進,以下為當前得物側在平臺歸因、端側監(jiān)控能力建設、端側問題治理上的一些實踐匯總。

平臺歸因問題平臺歸因問題

全局監(jiān)控能力建設全局監(jiān)控能力建設

端側優(yōu)化手段端側優(yōu)化手段

三、圖片庫監(jiān)控能力

圖片庫作為圖片請求的起始發(fā)起者 & 圖片加載的最終使用者,是唯一一個可以監(jiān)控、匯總完整鏈路數(shù)據(jù)的承載者。而得物當前的白屏監(jiān)控也是基于圖片加載流程深度剖析,形成了多圖、單圖的加載白屏監(jiān)控能力,將白屏問題拆解到多個細分子階段,輸出結構化的分析日志,最終打通到平臺側進行問題聚合分析。

圖片圖片

多圖監(jiān)控

定義為屏幕上10秒內(nèi)有7張圖未走完圖片庫的完整流程,則觸發(fā)多圖監(jiān)控上報。

基于Fresco的producer(階段信息)、reqeust(請求信息)、submit(加載信息)回調(diào)能力封裝,我們記錄了每一張圖片階段開始、結束、失敗、取消等詳細時間信息、額外圖片參數(shù)信息等到內(nèi)存Map中備用。

通過Handler消息循環(huán)模型,每秒發(fā)送1個探測消息,對加載成功、離開屏幕、內(nèi)存緩存復用等無關場景進行剔除過濾,達到監(jiān)控手機屏幕上失敗請求、加載中請求的目的,觸發(fā)到我們10s 7圖的閾值后則進行所有圖片信息的聚合上報,可以清晰直觀的知道圖片加載阻塞的卡點、失敗的原因。

圖片圖片

圖片核心信息記錄:

圖片圖片

  • Producer信息中記錄圖片經(jīng)歷所有任務處理階段:  線程切換、內(nèi)存緩存、磁盤緩存、網(wǎng)絡請求、編解碼等。
  • Request信息中記錄了圖片開始請求、取消、失敗的核心時間節(jié)點。
  • Submit信息中記錄了圖片上屏、完成加載、離開屏幕等核心時間節(jié)點。
  • PixelCopy信息記錄了最近一次屏幕的截屏信息,可以較為真實反應當前屏上圖片的時機情況,同時平臺對此進行了像素點的分析,本篇重點介紹圖片庫相關的監(jiān)控能力,在此不做過多的闡述。

以下為聚合格式化后圖片加載的本地日志與平臺實例參考,可以直接了當?shù)闹缊D片是由于網(wǎng)絡階段導致的白屏。

pixelCopy像素圖pixelCopy像素圖


圖片圖片

producer時序信息producer時序信息

單圖慢加載監(jiān)控

定義為單張圖3s內(nèi)未走完除網(wǎng)絡外的子階段、10s未完成完整階段,則觸發(fā)單圖慢加載上報。

單圖監(jiān)控的邏輯相對簡單,當圖片加載狀態(tài)變化時,基于圖片庫ImagePerfData的信息回調(diào)進行數(shù)據(jù)整合。

  • 記錄當前圖片加載階段、狀態(tài)、線程、耗時、單圖信息、配置信息等,仍舊通過handler消息循環(huán)每1s發(fā)送一個探測消息,確認屏上圖片是否觸發(fā)慢加載。

圖片圖片

大盤采樣監(jiān)控

等待圖片完整加載階段(成功、失敗)后基于用戶采樣命中,將圖片加載信息記錄上報,以衡量圖片全局加載質(zhì)量。

圖片大盤采樣監(jiān)控實現(xiàn)邏輯與多單圖原理類似,此處主要介紹一些大盤核心元信息。

圖片圖片

四、圖片庫優(yōu)化治理

基于圖片庫基礎監(jiān)控、白屏監(jiān)控平臺的建設以及線上用戶的反饋,我們發(fā)現(xiàn)了各種bad case導致端側白屏現(xiàn)象,并對其進行了精細化的點對點分析,包括圖片、網(wǎng)絡、CDN質(zhì)量三大環(huán)節(jié),其中66%為網(wǎng)絡問題,4.5%為圖片問題,1.3%為CDN問題。

本篇重點介紹圖片庫問題相關的治理優(yōu)化。

圖片圖片

系統(tǒng)解碼優(yōu)化

來看一個有意思的bad case,在線下bvt體驗過程中,我們發(fā)現(xiàn)在頻繁刷新得物Tab的情況下,會出現(xiàn)端上圖片均無法加載的極端情況。查看本地日志發(fā)現(xiàn),圖片庫的階段日志均停留在DecodeProducer解碼階段。


圖片圖片

通過本地多圖監(jiān)控日志可以看到,解碼線程池任務已經(jīng)提交,但實際解碼處理并沒有執(zhí)行,說明解碼線程池的當前執(zhí)行任務出了問題。

由于是線下問題,debug發(fā)現(xiàn)極個別圖片由于包含iccData數(shù)據(jù),按現(xiàn)有邏輯會執(zhí)行到系統(tǒng)解碼流程中。而在對應設備上(尤其是android 8.1.0)系統(tǒng)頻繁進行Heif解碼,整個解碼流程可能會變得極其緩慢。我們查看線程堆棧發(fā)現(xiàn)執(zhí)行任務會直接Block在BitmapFactory.nativeDecodeStream方法中,導致解碼線程池長時間阻塞,最終引起頁面白屏。

圖片圖片

  • iccData數(shù)據(jù): 圖片的顏色配置信息,告知端上渲染時的色彩特性。

現(xiàn)有LibHeif & 三方Heif解碼庫 均無法有效處理對應icc數(shù)據(jù)段,會導致個別圖片存在一定程度的色差問題。

優(yōu)化方案:

調(diào)整解碼流程,忽略iccData數(shù)據(jù)可能會導致的色差問題,將所有的解碼任務均托管到解碼庫執(zhí)行。

圖片圖片

收益:

新版本系統(tǒng)慢解碼(尤其android 8.1.0)導致的白屏未再出現(xiàn)。

圖片請求優(yōu)先級改造

為了提高屏上圖片加載速度,得物側使用了圖片預加載能力。在過往的預加載、上屏請求管理中,使用的是Fresco PriorityNetworkFetcher來處理預加載與上屏請求的優(yōu)先級,所有的圖片請求共享一個最大并發(fā)數(shù)為12的網(wǎng)絡請求隊列,這在實踐中我們發(fā)現(xiàn)了大量由于A域名不同,導致B域名請求無法成功導致的白屏。

圖片圖片

基于得物當前是多CDN、預加載&上屏請求互相轉換 的請求現(xiàn)狀,存在以下問題:

  • 多域名請求間的競爭問題,A域名不通會導致并發(fā)隊列被打滿,B域名網(wǎng)絡正常但請求始終處在等待入隊狀態(tài)。
  • 預加載進入請求隊列后,在弱網(wǎng)等狀態(tài)下并不能為上屏請求讓步,擠占了一部分的運行時請求隊列空間。
  • 預加載的請求會無上限堆積,快速滑動場景可能出現(xiàn)由于持續(xù)存在屏上圖片加載,預加載請求會堆積到200-300+,但實際并沒有有效利用到預加載轉化后的Bitmap,浪費了帶寬 & 流量。

優(yōu)化方案:

去除圖片庫的優(yōu)先級隊列限制,統(tǒng)一交由網(wǎng)絡庫管理收口。

  • 實現(xiàn)按域名拆解host請求,充分利用網(wǎng)絡庫的現(xiàn)有能力,打破域名間競爭。
  • 支持預加載、離屏的"請求取消"能力 & 圖片庫上離屏標記、請求狀態(tài)轉換。

圖片圖片

收益:

  • 端側圖片庫的請求平均排隊耗時降 88%,圖片請求全鏈路降低 50%。
  • 解決CDN單通導致的白屏問題,線上CDN單通異常數(shù)量呈下降趨勢。

動圖渲染幀處理重構

得物歷史對動圖渲染幀的準備、加載流程,不同于Fresco原生For循環(huán)實現(xiàn),自定義實現(xiàn)了利用Handler消息調(diào)度來分發(fā)、準備渲染幀。

問題發(fā)現(xiàn)

利用自研的白屏平臺監(jiān)控能力,聚合分析了圖片慢解碼導致白屏的Issue,發(fā)現(xiàn)有一類case用戶會出現(xiàn)解碼任務始終不完成的情況,出現(xiàn)概率大概在萬分之二。我們對解碼流程監(jiān)控進行了增強處理,進行線程池監(jiān)控,記錄解碼線程的運行數(shù)量、id、等待隊列數(shù)量等信息附帶在多圖監(jiān)控的白屏上報中。

圖片圖片

圖片圖片

可以看到,解碼線程池并發(fā)數(shù)8已經(jīng)被打滿,但等待隊列中囤積的解碼圖片數(shù)量有1200+。

白屏問題轉化為了監(jiān)控解碼線程池運行中的任務究竟在干什么,有了之前系統(tǒng)解碼的分析經(jīng)驗,我們?nèi)绻苯訉灼羻栴}當做一個Crash問題來分析呢?那么很自然地會想到去查看堆棧,只要dump運行時中的線程池id所對應的堆棧即可。

圖片圖片

最終通過堆棧結合代碼分析確認是由于動圖幀渲染的countDownLatch鎖在極端case下無法釋放,線程池逐步被打滿導致的等待隊列解碼任務無法得到執(zhí)行造成的白屏,而背景恰好是對應版本的動圖下發(fā)數(shù)量明顯上漲導致此類case逐漸暴露,與我們的結論能夠吻合。

圖片圖片

優(yōu)化方案

歷史代碼存在以下幾個問題:

  • 單幀Bitmap毫秒級的準備處理周期內(nèi),在View OnPause情況下未完成便退出,會導致當前線程鎖無法釋放。
  • countDownLatch的鎖邏輯可通過回調(diào)的方式代替。
  • 線程池復用解碼線程池,導致動圖加載邏輯異常會影響到所有圖片。

圖片圖片

圖片圖片

優(yōu)化后:對動圖幀渲染邏輯進行去鎖改造,采用callBack回調(diào)方式進行動圖幀分發(fā)處理,同時對解碼線程池進行隔離處理。

圖片圖片

收益:

App新版本動圖閉鎖邏輯導致的白屏歸因數(shù)量從原有1000+實現(xiàn)清零。

磁盤全局鎖優(yōu)化

圖片庫的磁盤設計基于Fresco原生實現(xiàn),支持大小緩存,但讀、寫、刪、遍歷操作同時共用Object Lock對象鎖,且過往由于業(yè)務需要獲取緩存文件的能力,圖片庫暴露了getCacheFile的API給到上層使用。

圖片圖片

白屏平臺發(fā)現(xiàn)存在磁盤讀寫超時導致的圖片白屏。通過對DiskProducer的深入代碼分析,我們將問題鎖定在了圖片庫存在大量本地磁盤文件的情況下,由于Fresco原生邏輯每隔30min要進行磁盤IO遍歷更新圖片庫當前磁盤緩存大小,可能會導致長時間持有對象鎖,最終引起圖片加載流程持續(xù)等待遍歷完成的白屏。

圖片圖片

優(yōu)化方案

磁盤遍歷是Fresco的磁盤緩存模型中唯一潛在的長耗時點。 

由于此操作的調(diào)用頻率極低(30min一次),我們嘗試針對IO遍歷進行標記,并調(diào)整了原有主線程獲取磁盤緩存文件 & Fresco原生磁盤緩存查找的邏輯,對于在緩存遍歷期間磁盤數(shù)量超過指定閾值的緩存讀取操作進行適當忽略。

當然終極優(yōu)化方案是降低磁盤緩存模型的鎖粒度,將全局的對象鎖降至單文件級別,但對現(xiàn)有的磁盤緩存設計改動過大暫時未上線。

圖片圖片

收益:

新版本磁盤鎖導致的主線程卡頓清零 & 磁盤鎖導致的圖片加載長耗時降低50% 。

元信息讀取適配 

部分設備上Heif圖編碼時獲取圖片metadata寬高元信息失敗,導致無法完成正常解碼、resize裁剪等操作,最終形成圖片加載白屏。

我們先來看下圖片庫歷史編碼流程環(huán)節(jié),在網(wǎng)絡請求完成后,會通過BitmapFactory進行圖片metadata信息,獲取期望的寬高數(shù)據(jù)。在歷史邏輯中,我們只單獨處理了webp圖片寬高讀取,Heif圖等其他格式仍舊采用系統(tǒng)兜底實現(xiàn),但實際針對加載失敗的原圖分析后,我們發(fā)現(xiàn)andorid系統(tǒng)BitmapFactory的解析邏輯對Heif圖片的支持并不友好,會存在獲取失敗的bad case。

final Pair<Integer, Integer> dimensions;
if (DefaultImageFormats.isWebpFormat(imageFormat)) {
  //webp圖片單獨處理  
  dimensions = readWebPImageSize();
} else {
  //系統(tǒng)兜底實現(xiàn)  
  dimensions = readImageMetaData().getDimensions();
}

故我們需要重Heif圖的寬高元信息獲取邏輯,實際獲取邏輯在三方SDK或者libHeif開源庫在native層完成了封裝,F(xiàn)resco上層走調(diào)用結構解析,分別對應寬度、高度、旋轉角度、旋轉方向、是否動圖等,同時在獲取解析結果異常的情況下,我們?nèi)耘f以系統(tǒng)BitmapFactory進行流解析兜底。

final Pair<Integer, Integer> dimensions;
if (imageFormat.getName().equals(DefaultImageFormats.HEIFC.getName())) {
  //部分設備的 系統(tǒng)實現(xiàn)讀取很慢且無法解析
  dimensions = readHeifFormatImageSizeForSimple(imageFormat);
} else if (DefaultImageFormats.isWebpFormat(imageFormat)) {
  dimensions = readWebPImageSize();
} else {
  dimensions = readImageMetaData().getDimensions();
}




//寬高、旋轉方向、是否為多幀hefi動圖等信息
try {
  int[] parseResult = imageFormat.readHeifFormatImageSizeForSimple(inputStream);
  if (parseResult != null) {
    this.mWidth = parseResult[0];
    this.mHeight = parseResult[1];
    this.mRotationAngle = JfifUtil.transformFromClockWiseToAntiClockWise(parseResult[2]);
    this.mExifOrientation = JfifUtil.getExifOrientationFromAutoRotateAngle(this.mRotationAngle);
    int isSequence = parseResult[3];
    if (isSequence == 0) {
      this.mImageFormat = imageFormat.getHeifFormatAnimated();
    }
  } else {
    //系統(tǒng)實現(xiàn)異常兜底  
    return readImageMetaData().getDimensions();
  }
} catch (Exception e) {
  e.printStackTrace();
} finally {
  try {
    inputStream.close();
  } catch (IOException ignored) {
  }
}

異常加載圖截屏異常加載圖截屏

開源libHeif的內(nèi)部實現(xiàn)開源libHeif的內(nèi)部實現(xiàn)

三方Heif的jni實現(xiàn)三方Heif的jni實現(xiàn)

至此,個別問題設備的Heif慢加載、無法加載問題得到了有效解決。

收益:

個別Rom設備dimension(圖片寬高)無法解析的異常上報基本清零,新版本該類型的白屏、慢加載從800+降至0。

內(nèi)存觸頂降級優(yōu)化

除了大面積白屏外,內(nèi)存不足導致的圖片加載失敗也是一個常見問題。

動圖降級

Fresco原生提供了PoolStatsTracker類來監(jiān)控在分配內(nèi)存過程中是否觸發(fā)到緩存池定義的內(nèi)存上限,定義了當前緩存池的使用量,以及onHardCapReached的觸頂回調(diào)。而我們當前則是在回調(diào)中,進行一次主動GC來保證系統(tǒng)回收未持有引用的bitmap & 其他內(nèi)存,同時標記規(guī)定間隔內(nèi)(如1min內(nèi))限制大動圖的內(nèi)存分配,將其強制轉為靜圖。

圖片圖片

圖片圖片

低內(nèi)存 & 低磁盤緩存清理

基于application ComponentCallbacks2的低內(nèi)存回調(diào)進行磁盤&內(nèi)存緩存清理。

override fun onLowMemory() {
    val imagePipeline = Fresco.getImagePipelineFactory().imagePipeline
    imagePipeline.config.executorSupplier.forBackgroundTasks().execute {
        if (DuImageGlobalConfig.isDiskNervous) {
            imagePipeline.clearDiskCaches()
        }
        imagePipeline.clearMemoryCaches()
    }
}


override fun onTrimMemory(level: Int) {
    val imagePipeline = Fresco.getImagePipelineFactory().imagePipeline
    imagePipeline.config.executorSupplier.forBackgroundTasks().execute {
        if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
            if (DuImageGlobalConfig.isDiskNervous) {
                imagePipeline.clearDiskCaches()
            }
        }
        if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
            imagePipeline.clearMemoryCaches()
        }
    }
}

其他內(nèi)存優(yōu)化手段

關于圖片內(nèi)存得物還做了很多優(yōu)化,但非觸頂場景下往往不會直接導致白屏,在此可以關注后續(xù)技術博客,如:

  • 三級緩存閾值配置分檔
  • Android8以下bitmap內(nèi)存轉移到Native層
  • 大動圖、大靜圖治理
  • 圖片Resize兜底裁剪、云端分級裁剪
  • BitmapConfig低端機降級
  • ....

主線程慢消息治理

在白屏平臺監(jiān)控中,還發(fā)現(xiàn)一類圖片庫已經(jīng)完成onFinalImageSet回調(diào),但最終pixelCopy的像素圖展示為白屏的情況。我們先來了解一下原有的圖片加載流程,根據(jù)流程可知我們已經(jīng)調(diào)用了圖片setImage設置,懷疑是頁面慢渲染導致的白屏。

圖片圖片

//圖片庫完成所有producer處理流程后的回調(diào)
private void onNewResultInternal(
    String id,
    DataSource<T> dataSource,
    @Nullable T image,
    float progress,
    boolean isFinished,
    boolean wasImmediate,
    boolean deliverTempResult) {
  //....
      if (isFinished) {
        logMessageAndImage("set_final_result @ onNewResult", image);
        mDataSource = null;
        if (mSettableDraweeHierarchy != null){
            mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate); //setImage調(diào)用
        }
        reportSuccess(id, image, dataSource);   //上報圖片完成屏上設置,即onFinalImageSet完成
      }
   //....   
 }

白屏問題隨即轉化為卡頓問題,分析卡頓問題的利器則是APM火焰圖能力,故我們對"圖片加載完成"但仍舊白屏的case進行火焰圖的聚合上報。發(fā)現(xiàn)主線程的確存在長耗時消息,問題最終轉化為了主線程的慢消息治理,以下列舉一下我們已經(jīng)發(fā)現(xiàn)并實際解決的問題。

圖片圖片

  • 頁面未接入X2c導致inflate耗時
  • GetCacheFile的主線程調(diào)用耗時
  • Sp的主線程強制寫文件
  • LoadSo成功后的字體文件主線程直接加載
  • 主線程查詢native視頻緩存
  • ....

收益:

主線程慢消息導致圖片View慢渲染白屏下降80%。

五、總結

白屏問題作為長鏈路綜合型問題,往往問題都是萬分之幾的出現(xiàn)概率,這意味著線下想要復現(xiàn)排查問題的難度極大,所以如何有效分析歸因解決白屏問題對我們來說是不小的挑戰(zhàn)。

在歷史監(jiān)控能力缺失無法有效歸因的背景下,我們通過線上白屏用戶的問題分析,一步步完善端側白屏全鏈路的日志能力,逐步摸索建立起基于端側圖片、網(wǎng)絡、CDN信息的白屏監(jiān)控平臺,實現(xiàn):

  • 白屏問題的線上反饋歸因率達到100%,無不明確或猜測的歸因;
  • 白屏問題的分析時效從無法分析到2-3小時級別,到現(xiàn)有的5-10min內(nèi);
  • 白屏問題線上反饋從歷史單月7~10例反饋,到截止目前2個月以來線上0反饋。

本文簡要介紹了在白屏監(jiān)控能力建設過程中,圖片庫在編解碼流程、緩存讀取策略、視圖渲染加載等階段所做的一些優(yōu)化。但白屏問題的治理遠遠不局限于圖片庫本身,后續(xù)會陸續(xù)為大家介紹我們在網(wǎng)絡優(yōu)化、CDN質(zhì)量監(jiān)控、白屏平臺打磨等環(huán)節(jié)所落地的實踐。

責任編輯:武曉燕 來源: 得物技術
相關推薦

2024-09-03 16:09:59

2023-08-30 18:49:05

2023-05-10 18:34:49

推薦價格體驗優(yōu)化UV

2023-07-19 22:17:21

Android資源優(yōu)化

2022-11-14 14:53:14

架構技術編輯工具

2025-04-02 02:10:00

2021-07-05 14:55:28

前端優(yōu)化圖片

2023-05-19 18:35:37

2023-05-15 18:33:09

得物前端巡檢

2023-03-30 18:39:36

2022-12-12 18:56:04

2021-10-09 20:18:31

Android

2022-12-05 19:15:12

得物云原生全鏈路

2023-10-09 18:35:37

得物Redis架構

2025-03-13 06:48:22

2023-04-28 18:37:38

直播低延遲探索

2023-08-21 19:37:21

得物DGraph引擎

2012-05-02 14:46:42

Win7

2023-11-27 18:38:57

得物商家測試

2023-02-08 18:33:49

SRE探索業(yè)務
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩精品免费一区二区在线观看 | 色成人免费网站 | 九九九国产 | 91视视频在线观看入口直接观看 | 国产日产久久高清欧美一区 | 特黄色一级毛片 | 老熟女毛片 | 不卡一区 | 免费a大片 | 亚洲成人国产综合 | 色女人天堂 | 一区二区三区国产好 | av毛片 | 一区二区三区在线免费 | 国产精品国产精品国产专区不卡 | 国产欧美精品区一区二区三区 | 国产精品无码久久久久 | av手机在线 | 欧美成人手机在线 | 91精品久久久久久久久中文字幕 | 久久99久久99精品免视看婷婷 | 一级片免费在线观看 | 美女黄视频网站 | 这里有精品 | 天堂色区 | 99精品视频一区二区三区 | 亚洲一区二区三区视频在线 | 91精品国产乱码久久久久久久久 | 日韩精品一区二区三区在线观看 | 成人免费网站www网站高清 | 深夜福利亚洲 | 日本久久久久久久久 | av日韩在线播放 | 亚洲成人a v| 久久精品视频网站 | 久久网站黄 | 欧美一区二区三区视频在线 | 日本一区二区三区四区 | 高清欧美性猛交 | 特黄特色大片免费视频观看 | 狠狠狠色丁香婷婷综合久久五月 |