征服Android面試官路漫漫(二):OutOfMemoryError 可以被 try catch 嗎 ?
問題由來:
這是一家公司的面試題目,感覺有點意思,所以面試回來準備測試下什麼情況。
問題論點:
對於這個問題,主要討論兩種OutOfMemory可能性,一種是突然使用了大量記憶體,比如載入了特別巨大的圖片,第二是記憶體洩漏。
然後還有個問題是,一旦發生OOM,引發OOM的操作是否會成功,如果會成功賦值是否會成功呢?理論上操作和賦值都不會成功的,但是我覺得有必要嘗試一下。
目錄
- OutOfMemoryError 可以被 try catch 嗎?
- 捕獲 OutOfMemoryError 有什麼意義?
- JVM 中哪一塊記憶體不會發生 OOM ?
OutOfMemoryError 可以被 try catch 嗎?
群裡小夥伴碰到的一道比較經典的面試題,但我相信很多第一次碰到這個問題的同學應該無法立刻給出答案,最好的辦法肯定還是動手測一測。
注意看下面的 Gif,每點選一次
Allocate 20MB ,都會給陣列容量增加
20*1024*1024
,當然應該並不是 20 MB。如下面程式碼所示:
當點選第 7 次時,發生了
OutOfMemoryError
,並且
catch
程式碼塊執行了。
Catch OOM : Failed to allocate a 146801680 byte allocation with 25165824 free bytes and 133MB until OOM, target footprint 153948888, growth limit 268435456
所以, OutOfMemoryError 是可以 try catch 的。
順道畫了一個思維導圖回顧一下 Java 的異常體系。
上面的圖片沒有羅列出所有的異常型別,但也基本概括了 Java 異常的繼承體系。所有的異常類都繼承自
Throwable
,
Throwable
有兩個直接子類
Error
和
Exception
。
Exception
一般指可以/應該捕獲和處理的異常。它的兩個直接子類
IOException
和
RuntimeException
及其子類都是我們在程式碼中經常遇到的一些錯誤。
RuntimeException
是在程式執行中可能發生的異常,我們可以不捕獲它,但可能帶來 Crash 的代價,但是過多的捕獲異常又不利於暴露和除錯異常情況。在開發過程中,我們更多的應該及時暴露問題。除了 RuntimeException 以外,其他異常可以統稱為
非執行時異常 或者
受檢異常,這些異常必須被捕獲,否則編譯期就會報錯。
Error
一般指非正常狀態的,比較嚴重的,不應該被捕獲的系統錯誤。
再回頭看看 OutOfMemoryError 的父類們,
OutOfMemoryError <- VirtualMachineError <- Error
OutOfMemoryError 是一個 Error ,Error 不應該被捕獲。那麼, 捕獲 OutOfMemoryError 有什麼意義呢?
捕獲 OutOfMemoryError 有什麼意義?
一般情況下並沒有什麼太大意義,相信你在開發中也幾乎沒有寫過 catch OOM 的程式碼。
如果你把捕獲 OOM 當做處理 OOM 的一種手段,無疑是不合適的。你無法保證你 catch 的程式碼就是導致 OOM 的原因,可能它只是壓死駱駝的最後一根稻草,甚至你也無法保證你的 catch 程式碼塊中不會再次觸發 OOM 。
我也從來沒有寫過捕獲 OOM 的程式碼,但無意中在 Android 原始碼中發現了這樣的操作。在
View.java
的
buildDrawingCacheImpl()
方法中有這麼一段程式碼:
buildDrawingCacheImpl()
方法的大致作用是為當前 View 生成一個 Bitmap 快取。在構建 Bitmap 物件的時候,如果捕捉到了 OOM ,就放棄生成 Bitmap 快取,因為在 View 的繪製過程中 Bitmap Cache 並不是必須存在的。所以在這裡沒有必要丟擲 OOM ,而是自己捕獲就可以了。
在你自己明確知道可能發生 OOM 的情況下設定一個兜底策略,這可能是捕獲 OOM 的唯一意義了。如果你有其他奇淫技巧,歡迎在評論區補充。
JVM 中哪一塊記憶體不會發生 OOM ?
最後補充一道我曾經遇到過的面試題, JVM 中哪一塊記憶體不會發生 OOM ?
當時面試的時候一下沒反應過來,回來之後翻了翻 《深入理解Java虛擬機器》 。但凡是 JVM 的相關問題,基本上都可以在這本書上找到答案。以下內容均總結摘抄自這本書,也可以檢視我的相關讀書筆記:第2章:Java記憶體區域與記憶體移溢位異常 。
Java 虛擬機器在執行 Java 程式的過程中會把它所管理的記憶體劃分為若干個不同的資料區域,如下圖所示:
Java 虛擬機器棧 。每個方法被執行的時候,Java 虛擬機器棧都會同步建立一個棧幀用於儲存區域性變數表、運算元棧、動態連線、方法出口等資訊。每個方法被呼叫直到執行完畢的過程,就對應著一個棧幀在虛擬機器棧中從入棧到出棧的過程。
如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲 StackOverflowError 異常。如果 Java 虛擬機器棧支援動態擴充套件,當棧擴充套件時無法申請到足夠的記憶體會排丟擲 OutOfMemoryError 異常。
本地方法棧。為虛擬機器使用到的 Native 方法服務。《Java 虛擬機器規範》對本地方法棧中方法使用的語言、使用方式和資料結構並沒有任何強制規定,因此具體的虛擬機器可以根據需要自由實現它。Hotspot 將本地方法棧和虛擬機器棧合二為一。
本地方法棧也會在棧深度溢位和棧擴充套件失敗時分別丟擲 StackOverflowError 和 OutOfMemoryError 。
Java 堆。所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。此記憶體區域的唯一目的就是存放物件例項,Java 世界裡 “幾乎” 所有的物件例項都在這裡分配記憶體。在 《Java 虛擬機器規範》中對 Java 堆的描述是:“所有的物件例項以及陣列都應當在堆上分配”。
Java 堆以處於物理上不連續的記憶體空間,但在邏輯上它應該被視為連續的。但對於大物件(典型的如陣列物件),多數虛擬機器實現出於實現簡單、儲存高效的考慮,很可能會要求連續的記憶體空間。
Java 堆既可以被實現成固定大小,也可以是擴充套件的。如果在 Java 堆中沒有記憶體完成例項分配,並且堆無法再擴充套件時,Java 虛擬機器將會丟擲 OutOfMemoryError 。
方法區。方法區是各個執行緒共享的記憶體區域,它用於儲存已被虛擬機器載入的型別資訊、常量、靜態變數、即時編譯器編譯後的程式碼快取等資料。
雖然《Java 虛擬機器規範》中把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做“非堆”,目的是與 Java 堆分開來。
Hotspot 設計之初選擇把垃圾收集器的分代設計擴充套件至方法區,或者說使用永久代來實現方法區而已,使得 HotSpot 的 GC 能夠像管理 Java 堆一樣管理這部分記憶體,但導致 Java 應用更容易遇到記憶體溢位的問題。在 JDK 8 中,徹底廢棄了永久代的概念。
如果方法區無法滿足新的記憶體分配的需求時,將丟擲 OutOfMemoryError 。
執行時常量池。方法區的一部分。Class 檔案的常量池表,用於存放編譯期生成的各種字面量與符號引用,這部分內容將在類載入後方法方法去的執行時常量池。
執行時常量池具有動態性,執行期間也可以將新的常量放入池中,如 String.intern() 。
常量池受到方法區的限制,當無法再申請到記憶體時,會丟擲 OutOfMemoryError 。
唯一一個在《Java虛擬機器規範》中沒有規定任何 OutOfMemoryError 情況的區域是 程式計數器。程式計數器(Program Counter Register)是一塊較小的記憶體空間,它可以看作是當前執行緒所執行的位元組碼的行號指示器。如果執行緒正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;如果正在執行的是本地(Native)方法,這個計數器值則應為空(Undefined)。
征服Android面試官路漫漫
有些東西你不僅要懂,而且要能夠很好地表達出來,能夠讓面試官認可你的理解,例如Handler機制,這個是面試必問之題。有些晦澀的點,或許它只活在面試當中,實際工作當中你壓根不會用到它,但是你要知道它是什麼東西。
對於程式設計師來說,要學習的知識內容、技術有太多太多,要想不被環境淘汰就只有不斷提升自己, 從來都是我們去適應環境,而不是環境來適應我們!
最後我在這裡分享一下這段時間從朋友,大佬那裡收集到的一些
2019-2020BAT 面試真題解析,裡面內容很多也很系統,包含了很多內容:
Android 基礎、Java 基礎、Android 原始碼相關分析、常見的一些原理性問題
等等,可以很好地幫助我們深刻理解Android相關知識點的原理以及面試相關知識。
1、確定好方向,梳理成長路線圖
不用多說,相信大家都有一個共識:無論什麼行業,最牛逼的人肯定是站在金字塔端的人。所以,想做一個牛逼的程式設計師,那麼就要讓自己站的更高,成為技術大牛並不是一朝一夕的事情,需要時間的沉澱和技術的積累。
關於這一點,在我當時確立好Android方向時,就已經開始梳理自己的成長路線了,包括技術要怎麼系統地去學習,都列得非常詳細。
知識梳理完之後,就需要進行查漏補缺,所以針對這些知識點,我手頭上也準備了不少的電子書和筆記,這些筆記將各個知識點進行了完美的總結:
2、透過原始碼來系統性地學習
只要是程式設計師,不管是Java還是Android,如果不去閱讀原始碼,只看API文件,那就只是停留於皮毛,這對我們知識體系的建立和完備以及實戰技術的提升都是不利的。
真正最能鍛鍊能力的便是直接去閱讀原始碼,不僅限於閱讀各大系統原始碼,還包括各種優秀的開源庫。
3、閱讀前輩的一些技術筆記
4、刷題備戰,直通大廠
歷時半年,我們整理了這份市面上最全面的安卓面試題解析大全
包含了騰訊、百度、小米、阿里、樂視、美團、58、360、新浪、搜狐等一線網際網路公司面試被問到的題目。熟悉本文中列出的知識點會大大增加透過前兩輪技術面試的機率。
如何使用它?
1.可以透過目錄索引直接翻看需要的知識點,查漏補缺。
2.五角星數表示面試問到的頻率,代表重要推薦指數
以上文章中的資料,均可以免費分享給大家來學習,無論你是零基礎還是工作多年,現在開始就不會晚。
以上內容均放在了開源專案: 【 github 】 中已收錄,大家可以自行獲取。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983917/viewspace-2731736/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程Android面試
- 征服Android面試官路漫漫(三):從原始碼深扒一下四大元件和 ContextAndroid面試原始碼元件Context
- Laravel try catchLaravel
- js try catchJS
- iOS的@try、@catch()iOS
- 【搞定面試官】try中有return,finally還會執行嗎?面試
- Java try catch finallyJava
- 一文吃透Volatile,征服面試官面試
- 征服面試官:OkHttp 原理篇 掌握這篇面試題彙總,吊打面試官!HTTP面試題
- c++ try catch 問題C++
- 面試官:Java執行緒可以無限建立嗎?面試Java執行緒
- 如果我是Android面試官二Android面試
- 金三銀四,如何征服面試官,拿到Offer面試
- (十四).try-throw-catch機制
- JavaScript try catch finally 語句JavaScript
- js中try和catch的用法JS
- JavaScript錯誤_throw、try和catchJavaScript
- Java try catch finally 總結Java
- JavaScript try/catch/finally 語句JavaScript
- 微軟:請不要使用 Try/Catch微軟
- java中try catch塊的使用Java
- 【C#之Try……Catch例項】C#
- 一張圖搞清楚wait、sleep、join、yield四者區別,面試官直接被征服!AI面試
- JS 使用try catch捕獲異常JS
- Java之異常處理try{}catch(){}Java
- Java中try()catch{}的使用方法Java
- 漫漫前端路前端
- try throw catch 語句檢測input值
- java try(){}catch(){}自動資源釋放Java
- IDEA 自動生成try,catch快捷鍵Idea
- c++中的try-catch及throwC++
- 面試官:x !== x 可以為 true ?面試
- 面試官:小夥子,能聊明白JMM給你SSP!我:嘚吧嘚吧一萬字,直接征服面試官!面試
- Java之try-catch和throws的區別Java
- JavaScript 中 try...catch 的 10 個使用技巧JavaScript
- NodeJS 實戰系列:如何設計 try catchNodeJS
- Nodejs try catch捕捉異常失效場景NodeJS
- SQL SERVER 裡的錯誤處理(try catch)SQLServer