說說JVM原理?記憶體洩漏與溢位的區別?何時產生記憶體洩漏?
1、JVM原理
JVM是Java Virtual Machine(Java虛擬機器)的縮寫,它是整個java實現跨平臺的最核心的部分,所有的Java程式會首先被編譯為.class的類檔案,這種類檔案可以在虛擬機器上執行,也就是說class並不直接與機器的作業系統相對應,而是經過虛擬機器間接與作業系統互動,由虛擬機器將程式解釋給本地系統執行。JVM是Java平臺的基礎,和實際的機器一樣,它也有自己的指令集,並且在執行時操作不同的記憶體區域。JVM通過抽象作業系統和CPU結構,提供了一種與平臺無關的程式碼執行方法,即與特殊的實現方法、主機硬體、主機作業系統無關。JVM的主要工作是解釋自己的指令集(即位元組碼)到CPU的指令集或對應的系統呼叫,保護使用者免被惡意程式騷擾。JVM對上層的Java原始檔是不關心的,它關注的只是由原始檔生成的類檔案(.class檔案)。
2、記憶體洩漏與溢位的區別
-
記憶體洩漏是指分配出去的記憶體無法回收了。
-
記憶體溢位是指程式要求的記憶體,超出了系統所能分配的範圍,從而發生溢位。比如用byte型別的變數儲存10000這個資料,就屬於記憶體溢位。
-
記憶體溢位是提供的記憶體不夠;記憶體洩漏是無法再提供記憶體資源。
3、何時產生記憶體洩漏
-
靜態集合類:在使用Set、Vector、HashMap等集合類的時候需要特別注意,有可能會發生記憶體洩漏。當這些集合被定義成靜態的時候,由於它們的生命週期跟應用程式一樣長,這時候,就有可能會發生記憶體洩漏。
-
監聽器:在Java中,我們經常會使用到監聽器,如對某個控制元件新增單擊監聽器addOnClickListener(),但往往釋放物件的時候會忘記刪除監聽器,這就有可能造成記憶體洩漏。好的方法就是,在釋放物件的時候,應該記住釋放所有監聽器,這就能避免了因為監聽器而導致的記憶體洩漏。
-
各種連線:Java中的連線包括資料庫連線、網路連線和io連線,如果沒有顯式呼叫其close()方法,是不會自動關閉的,這些連線就不能被GC回收而導致記憶體洩漏。一般情況下,在try程式碼塊裡建立連線,在finally裡釋放連線,就能夠避免此類記憶體洩漏。
-
外部模組的引用:呼叫外部模組的時候,也應該注意防止記憶體洩漏。如模組A呼叫了外部模組B的一個方法,如:public void register(Object o)。這個方法有可能就使得A模組持有傳入物件的引用,這時候需要檢視B模組是否提供了去除引用的方法,如unregister()。這種情況容易忽略,而且發生了記憶體洩漏的話,比較難察覺,應該在編寫程式碼過程中就應該注意此類問題。
-
單例模式:使用單例模式的時候也有可能導致記憶體洩漏。因為單例物件初始化後將在JVM的整個生命週期記憶體在,如果它持有一個外部物件(生命週期比較短)的引用,那麼這個外部物件就不能被回收,而導致記憶體洩漏。如果這個外部物件還持有其它物件的引用,那麼記憶體洩漏會更嚴重,因此需要特別注意此類情況。這種情況就需要考慮下單例模式的設計會不會有問題,應該怎樣保證不會產生記憶體洩漏問題。