本文主要總結(jié)java虛擬機的內(nèi)存管理機制,不同的數(shù)據(jù)類型存在在怎樣的一塊內(nèi)存區(qū)域中,不同的內(nèi)存區(qū)域有哪些不同點,怎樣回收過了生命周期的內(nèi)存,采取何種策略去回收這些對象或者常量,不同的回收算法的優(yōu)缺點.什么情況下會產(chǎn)生內(nèi)存溢出異常以及該采取怎樣的措施避免內(nèi)存溢出,以及一些常用的虛擬機性能監(jiān)控工具和故障排除工具
-<<深入理解java虛擬機>>讀書筆記
jvm內(nèi)存區(qū)域
虛擬機管理的運行時數(shù)據(jù)區(qū)域如下圖所示
方法區(qū)
方法區(qū)是各個線程共享的內(nèi)存區(qū)域(這樣就能理解為什么需要線程同步和加鎖了,當然還與java數(shù)據(jù)訪問時數(shù)據(jù)復制來復制去有關),用于存儲已被虛擬機加載的類信息,常量,靜態(tài)變量,JIT即時編譯后的代碼等.
方法區(qū)的數(shù)據(jù)類型復雜,而且jvm規(guī)范也沒有明確指定方法區(qū)的內(nèi)存使用和回收策略,所以不同的虛擬機對于方法區(qū)的內(nèi)存回收都有不同的機制.下文介紹.
運行時常量池
運行時常量池是方法區(qū)的一部分,存儲編譯時或者運行時產(chǎn)生的字面常量或者其他信息.
堆
堆也是被各個線程共享的內(nèi)存區(qū)域,虛擬機主要管理的內(nèi)存區(qū)域,是java存放對象數(shù)據(jù)的地方,這里面也有指針,因為對象數(shù)據(jù)里面可能還有其他對象的引用,還有方法區(qū)常量池常量的引用.還有數(shù)組也是在堆上分配內(nèi)存.
虛擬機棧
線程私有,與線程同生同滅.用于存儲java運行時的內(nèi)存模型,也就是每個方法執(zhí)行時的一個棧幀,該棧幀存儲了局部變量表,操作數(shù)棧,動態(tài)鏈表,方法出口等運行時信息.
對于一個方法開始執(zhí)行到執(zhí)行結(jié)束就是一個棧幀在虛擬機中入棧和出棧的過程.
程序計數(shù)器
和虛擬棧幀一樣,該內(nèi)存區(qū)域的生命周期也是在一個線程的執(zhí)行周期內(nèi).可以看作當前線程執(zhí)行字節(jié)碼行號的指示器,字節(jié)碼的解釋執(zhí)行工作就是通過這個來確定循環(huán),判斷,跳轉(zhuǎn),異常處理以及線程恢復等功能.
每個線程擁有一個獨立的程序計數(shù)器內(nèi)存區(qū)域可以使得多線程環(huán)境下線程能接著上一個時間片繼續(xù)執(zhí)行.
本地方法棧
本地方法棧與虛擬機棧的作用幾乎相同,不同的地方在于虛擬機棧用于服務java方法,而本地方法棧可以描述native方法,即虛擬機規(guī)范規(guī)定的可使用的其他語言.
直接內(nèi)存
直接內(nèi)存不是虛擬機運行時數(shù)據(jù)取的一部分
在jdk1.4后引入了一種通道和緩沖區(qū)的I/O方式,使用native函數(shù)庫直接分配堆外內(nèi)存,然后通過一個存儲在java堆中的DirectByteBuffer對象作為這塊內(nèi)存的引用直接進行操作,這樣能在一定的場景下顯著提高性能,避免了在java堆中和native堆中來回復制數(shù)據(jù).
數(shù)據(jù)在上述內(nèi)存區(qū)域的分布
對象的兩種不同訪問形式
這樣看句柄就是一系列的指針和其他數(shù)據(jù)組成的數(shù)據(jù)結(jié)構(gòu),果然是要好好學習數(shù)據(jù)結(jié)構(gòu)
jvm內(nèi)存溢出
內(nèi)存溢出即指上述內(nèi)存區(qū)域存放的數(shù)據(jù)結(jié)構(gòu)的總量大于限制的最大大小,導致虛擬機跑出內(nèi)存溢出異常.
虛擬機垃圾收集器
如何判斷對象需要被回收削解?
對于不同的算法有不同的判斷方式
堆中垃圾回收算法
引用計數(shù)算法
給每個對象添加一個引用計數(shù)器炮车,每當有一個地方引用它時淫茵,計數(shù)器加一嗓蘑,引用失效則減一。
優(yōu)點:實現(xiàn)簡單吧趣,判斷效率高
缺點:當對象存在相互引用時和悦,不能夠回收此類對象
可達性分析算法
可達性算法的核心在于找到一系列的根節(jié)點,并且判斷對象到這些根節(jié)點是否可達榜揖。
可作為根節(jié)點的對象有:
- 虛擬機棧中引用的對象
- 方法取中靜態(tài)屬性引用的對象
- 方法取中常量引用的對象
- 本地方法棧中JNI引用的對象
四種引用
強引用-軟引用-弱引用-虛引用
方法區(qū)中垃圾回收算法
標記-清除算法
首先標記出所有需要回收的對象勾哩,在標記完成后統(tǒng)一進行回收,但是缺點就是會造成大量的內(nèi)存碎片举哟。導致之后給大的對象分配內(nèi)存無可用空間思劳。
復制算法
將可用的內(nèi)存分為兩半,一次只使用其中的一半妨猩,當使用完以后潜叛,將還活著的對象全部復制到另一半內(nèi)存空間中,然后清理掉原來的那半內(nèi)存壶硅,缺點就是代價太高钠导,需要犧牲一半的內(nèi)存震嫉。
標記-整理算法
將所有的對象像一端移動,然后直接清理掉其他的對象(98%的對象生命周期都很短)