本文在 B 站有對應的視頻,若是你喜歡看視頻版本,能夠點 這裏 去嗶哩嗶哩觀看,或者點 這裏 去 YouTube 觀看。程序員
面試官:你作過性能優化是吧。web
面試者:嗯是的,在卡頓和耗電問題上作過挺多事。面試
面試官:內存抖動的解決方案你有了解過嗎?性能優化
面試者:內存什麼?編輯器
面試官:內存抖動。沒有聽過嗎?ide
面試者:……沒有。性能
面試官:呼(搖頭)。年輕人仍是要敬畏技術啊,要持續學習啊。學習
面試者:我……嗯……優化
你們好,我是扔物線朱凱。spa
看起來很酷的詞老是容易吸引眼球,好比「雙親委託」,好比「責任鏈」,好比——「內存抖動」。吸引眼球就意味着會有更多點擊,而點擊量是內容創做者最愛的東西,因此這些名字很酷的詞就很天然地會受到各類技術文章的偏心,由於你寫這些文章能夠獲得更多的流量,這是無可厚非的。強調一下,這是無可厚非的。但有些做者對於流量的追求過於偏執,什麼東西都喜歡過度地吹一下。
你們做爲讀者,看文章的時候要有辨別力,不要被這些流量詞帶偏,更不要被某些流量販子們騙得去加到本身的面試題裏來考驗你的面試者是否讀過某篇文章,這是沒有價值的。
啊啊?「內存抖動」這個概念居然沒價值?
不是的 ,我不是說內存抖動的概念沒價值。哎算了,我先說一下什麼是內存抖動吧:
在程序裏,每建立一個對象,就會有一塊內存分配給它;每分配一塊內存,程序的可用內存也就少一塊;當程序被佔用的內存達到必定臨界程度,GC 也就是垃圾回收器(Garbage Collector)就會出動,來釋放掉一部分再也不被使用的內存。Android 裏的 View.onDraw() 方法在每次須要重繪的時候都會被調用,這就意味着,若是你在 onDraw() 裏寫了建立對象的代碼,在界面頻繁刷新的時候,你就也會頻繁建立出一大批只被使用一次的對象,這就會致使內存佔用的迅速攀升;而後很快,可能就會觸發 GC 的回收動做,也就是這些被你建立出來的對象被 GC 回收掉。垃圾內存太多了就被清理掉,這是 Java 的工做機制,這不是問題。問題在於,頻繁建立這些對象會形成內存不斷地攀升,在剛回收了以後又迅速漲起來,那麼緊接着就是又一次的回收,對吧?這麼往復下來,最終致使一種循環,一種在短期內反覆地發生內存增加和回收的循環。
這種循環往復的狀態就像是水波紋的顫動同樣,它的專業稱呼叫作 Memory Churn,Android 的官方文檔裏把它翻譯作了內存抖動。因此內存抖動其實並非咱們的內存在總體地進行搖晃這樣神奇的事情,
而僅僅是相似有一根攪拌棒輕輕地在內存的邊界上進行攪動的樣子——其實翻譯成「內存攪動」好像也行哈?
咱們也能夠經過 Android Studio 的 Memory Profiler 來更直觀地觀察到這種現象:
內存的回收雖然很快,時間成本很低,但終究是有時間成本的。一兩次內存回收不容易被用戶察覺,但屢次內存回收行爲集中在短期內爆發,這就形成了比較大的界面卡頓的風險。這也是爲何 Android 在官方文檔和 Android Studio 裏都建議咱們儘可能避免在 onDraw() 裏建立對象。
一樣的道理,不僅是在 onDraw(),在次數比較大的循環裏建立對象,一樣會致使內存抖動。不過由於在實踐中,咱們在 onDraw() 裏建立的對象每每是繪製相關的對象,而這些對象又常常會包含通往系統下層的 Native 對象的引用,這就致使在 onDraw() 裏建立對象所致使的內存回收的耗時每每會更高,直白地說就是——界面更卡頓。
另外呢內存抖動有時候也會抖着抖着就變成內存溢出了,這就是更嚴重的狀況,由於內存溢出的直接結果就是軟件崩潰。
因此,「內存抖動」這個概念有價值嗎?
固然有價值了,由於這個詞幫助咱們很形象地去形容了程序中的一種現象。對吧?增長、回收、增長、回收。
那麼我在開頭說的「沒價值」,指的是什麼呢?
我說的不是「內存抖動」的概念沒價值,而是追求對這個概念自己的瞭解是沒價值的。確切地說是,面試官們企圖用是否知道「內存抖動」這樣的詞來考察面試者是否具備高開發水平這樣的面試策略,是沒價值的。內存優化是一個很複雜很細碎的話題,而在 onDraw() 中避免建立對象只是其中的冰山一角。並且就算在這冰山一角里,重點也只在於「避免內存增加」,而不是「避免內存抖動」。內存抖動只是一種具體的表面現象而已,而這種現象背後的緣由,除了在 onDraw() 中建立對象,也不多再有其餘場景了。那麼這種場景限定極強的詞被專門列出來在面試題裏,又有什麼意義呢?
我不是在說你面試的時候不該該問內存抖動,而是說你的注意力必定不能放在這個詞上。聽沒據說過內存抖動並不重要,知道內存抖動的緣由和解決方案才重要。
嗯……沒聽過內存抖動,怎麼會知道它的緣由和解決方案?
他沒聽過你能夠告訴他呀!不是不能問內存抖動,而是若是你問了以後對方表示沒聽過,你應該進一步引導,好比你問他:那麼,Android 官方建議咱們不要在 onDraw() 裏建立對象你知道嗎?你知道爲何嗎?若是他當即回答這會致使頻繁觸發內存回收,那不是證實他其實懂原理的嗎?這時候你再告訴他,這就叫內存抖動,就好了。
並且也不要侷限於這一個詞,你還能夠繼續問:爲何在 onDraw() 裏建立對象致使的結果是內存抖動而不是內存溢出?這種對於能力的考察比對詞彙的考察重要多了。其實我也不是很肯定這個問題是否是每一個喜歡問內存抖動的面試官們都能回答上來,但這樣問纔是考察程序員能力的最好方式。
若是你在面試時問了內存抖動,但在對方表示沒聽過以後,你就再也不進行任何的引導而是直接給對方扣了分,那你其實至關於在問:我這裏有一個高端詞彙,您聽過嗎?
我在上課的時候,常常跟學員強調學技術要學本質,由於有些地方我講得比較深我怕他們不學。說到個人課,有想學 Android 高級進階系列化知識的,掃碼諮詢。
我怎麼以爲個人廣告有點六學?過渡一點也不優雅,強行轉彎,強勢恰飯。下次改進下次改進。
說回到本質,學技術要學本質,但內存抖動並非任何技術的本質。其實我今天也並非在聊內存抖動這個詞自己,而是想表達一種觀點:
咱們學技術,應該學得深,並且應該足夠深,但不要被各類花裏胡哨的詞嚇到,也不要被它們帶着跑,咱們要有本身的知識體系,有本身的成長邏輯。
我是扔物線,我不和你比高低,我只助你成長。咱們下期見。
本文使用 mdnice 排版