一線大廠資深APP效能優化系列 啟動優化總結(五)

2021-10-06 20:35:04 字數 3758 閱讀 2608

最近感覺真的很懶惰,答應幾個小夥伴的更新,也遲遲沒更,今天給補上。這一章主要是對前4章學習的總結

這四章其實也是啟動優化這乙個大章節的內容,看完這4個,至少啟動優化這個地方就已經很ok了。

當然接下來我們會進入 第二大章節的內容學習了,第二大章節,預計有5個小章節組成,是全套介紹在乙個真實專案中的如何進行記憶體優化 希望大家能提前先了解下關於記憶體優化這方面的知識。

當然了,之前也吐槽過,學習一定要紮實,很多人對於記憶體優化這方面的內容的理解就是:leakcanary的使用及原理,但是檢測出來如何優化?如何避免這些問題,這就是經驗了

這是我們第一大章中的第一小章,具體看

在這一章我們主要講的就是如何獲取方法耗時,工欲善其事,必先利其器,這也是日常我們進行大專案優化的第一步,先分析一下這個大專案的耗時情況,有很多同學反映說是進行老專案維護公升級,卡頓無從下手,所以分析卡頓的耗時時間就是進行專案優化的第一步。

1.常規方式

直接在每個方法上下各加入一行**,然後列印,如:

public

void

func()

簡單是簡單,但是記住我們做效能檢測的,是不能寫這種入侵性很強的**,很有可能本來很穩定的系統,因為你的效能檢測的**,變成了不穩定,這是不被允許的。所以廢棄!

2.aop方式

這種方式尼,可以使得我們的效能檢測**與邏輯**相分離

@aspect

public

class

performanceaop

catch

(throwable throwable)

log.d(

"lybj"

, methodname +

"方法耗時:"

+(system.

currenttimemillis()

- starttime));

}}

缺點: 如果專案比較龐大,上百個方法,總不能全部打點,然後乙個乙個的分析到底是哪個地方執行時間過長吧,所以我們需要乙個比較直觀的工具,一眼就能看到具體哪個方法執行時間過長。

3.wall time 與 cpu time

在traceview裡面的時間模式有兩種:

wall time 就是執行這段**的時間,但是如果該執行緒被卡住了,等待的時間也是被算在內的。

cpu time(thread time) 則是cpu具體花在這個執行緒上的時間,它的時間也一定小於wall time的時間,

所以如果發現wall time 時間很長,cpu time時間很短,那麼就說明了一件事,你需要開非同步執行緒了,因為耗時的主要原因都是,cpu在閒置,而你的執行緒在等待。

可以使用執行緒池或者開啟執行緒去實現,目的很簡單,為了幫主執行緒分擔壓力。

缺點:1.如果兩個非同步之間執行的內容有著依賴關係,則不好處理

比如我們要初始化極光推送,還要獲取裝置id,假如這兩個都是耗時方法,均需要在子執行緒中進行初始化,但是必須得先獲取裝置id,再初始化極光推送,兩者之間存在依賴關係,則不是很好處理了,具體檢視第二章節內容。

缺點:2.如果其中乙個非同步處理,需要先執行完畢自己,主線程才能繼續往下執行,那麼常規方式也不好處理。

缺點:3.如果上面兩個你通過同步鎖機制都處理了,那麼恭喜你,你的**可讀性肯定不高!

還記得嗎,咱們一起實現了個啟動器,原理很簡單,具體看第三章,這裡只是簡述:

task

首先是將我們的耗時操作均封裝成乙個task,它有4個方法1個屬性

屬性1 :taskcountdownlatch,該task有幾把鎖尼,取決於它的依賴的task集合數。

方法1 :dependentarr()返回它所依賴的task集合

方法2 :startlock()開啟鎖

方法3 :unlock()執行完乙個依賴,減少一把鎖

方法4 :needwait() 是否需要主線程等你執行完再執行

啟動器(taskmanager)

啟動器主要是用來分發task的

屬性1:mcountdownlatch 鎖,不同於task裡的鎖,這個鎖是鎖主線程的,當主線程呼叫它時,它會鎖定,鎖的數量取決於等待計數器(mainneedwaitcount)的數量

方法1:add: 將task新增至集合中,並以需要依賴的物件為key,集合為value建立乙個map,這個map是做什麼的尼?主要啊,當乙個task執行完畢,就可以迴圈這個map找到這個執行完畢的task,獲取到需要依賴它的物件集合,然後讓每乙個物件,均減少一把鎖。然後呼叫這個task的needwait()方法,看看是否需要主線程等待它,如果需要,等待計數器+1

方法2:starttask:分發task,首先是根據有向無環圖的拓撲排序,將task集合重新排序,比如,我們傳入的任務是a,b,c但是尼,如果a依賴於b,那麼就需要先初始化b,同時處理c,然後再處理a。返回就是b、c、a。設定主線程的鎖,鎖的數量等待集合數量,保證一些要切換頁面之前必須要執行完的task均執行完。然後根據所要求的執行緒進行分發處理。

執行器(taskrunnable)

執行器主要就是為了執行task的,它繼承了runnable

方法1:run(): 啟動task裡面的鎖,還記得不,它的鎖的數量取決於它所依賴的物件數,目的就是先執行完它的依賴。然後尼,執行task裡面的run方法,這個是個空方法,用於執行我們的耗時任務,然後執行啟動器的unlockforchildren方法,還記得嗎,就是用來迴圈之前存的map找到這個執行完畢的task,獲取到需要依賴它的物件集合,然後讓每乙個物件,均減少一把鎖。

是不是很簡單?不理解的就去研究第三章內容,熟讀並背誦

涉及到一章內容,如下:

可以通過handler().sendmessagedelayed() 達到延遲載入

但是專案中是不建議這樣用的,因為會搶占cpu,效能會進行耗損,比如乙個頁面的一些第三方服務進行初始化操作,雖然說是可以延遲一段時間再去初始化,但是如果該頁面有任務一直在執行,比如有個定時器或者輪詢請求介面等,那麼延時的時間到了,依然是要搶占cpu來執行我們的第三方服務的初始化操作。所以不能直接這麼用

這個是沒問題的,可以在cpu空閒時間進行處理耗時操作,但是如果加入的任務存在著先後執行順序等,就無法單純的使用它了,因為它是無序的,加入的任務是誰有空執行誰

具體看第四章節內容,這裡只是簡介

ildetaskmanager

原理很簡單,有乙個方法add()作用就是把task新增到集合裡面,然後封裝乙個ildehandler,遍歷這個集合,取得task後,交給taskrunnable去執行它,taskrunnable就是我們第三章節時封裝的。

好了,這裡有大家最期待的原始碼

記得點個星!

愉快的假期生活完事了,公司要求復工了,真是乙個悲傷的故事。

經過了乙個月,總算是把第一大章節啟動優化的內容更新完了,基本也就這些內容,在網上查了查雖然還有很多,比如預載入位元組碼檔案等,但是尼,其實感覺沒必要,乙個軟體快了0.1秒其實是作用不大的,還有的說是鎖定cpu的頻率,但是你就無法保證節約電量的作用,當然還有些適配方案,但是經過驗證,要麼沒什麼效果,要麼有些華而不實。基本上掌握了上述的4個章節,啟動優化就夠了,即便是大廠優化到這個程度也是可以了。

接下來的幾周會給大家更新第二大章節的內容,涉及的是在實戰專案中關於記憶體的優化方案。大家記得要複習一下!

2023年一線大廠面試題精選

題目 mysql索引相關,使用 mysql 索引都有哪些原則?索引什麼資料結構?b tree 和 b tree 什麼區別?mysql中有哪些搜尋引擎?高併發系統資料庫層面應該如何設計?資料庫鎖有哪些型別,應該如何實現?資料庫事務有哪些?oracle常用函式有哪些?sql中有哪些情況不會走索引?說說對...

優化APP效能(一)

我們都知道如何在android中建立乙個執行緒,如下 new thread new runnable start 但是這樣子建立執行緒有乙個缺點就是當乙個專案非常大,很多地方都需要開啟子執行緒去執行任務的時候,不斷建立執行緒對於系統的開銷還是非常大的,一定程度上影響系統效能。那麼我們如何才能提高執行...

《一線大廠如何面試前端工程師》聽後感

這是由三個人聯合主講的面試經驗非技術帖。康康的分享 從平台的角度 康康陳述得挺流暢,音色也不錯。很書面化,像個正式的主持人。簡歷硬條件 面試要點 面試流程 winter的分享 從面試者的角度 小吐槽 溫大神的ppt做得真的很一般。草根如何準備簡歷 案例 沒成就的寫案例 心得 案例實在也沒有寫心得 面...