《深入理解Java虛擬機》第二三章摘要
Java內存區域與內存溢出
Java虛擬機中的內存分配圖:
各個區域的特性總結如下表:
補充說明:
內存分配方式:虛擬機使用哪種方式由內存是否規整決定,而內存是否規整則由回收算法決定。
對象在HotSpot虛擬機中的內存布局如下表所示:
在Java規范中,對於reference類型只規定了一個指向對象的引用,但沒有規定通過何種方式去訪問引用的數據。因此對於不同的虛擬機也有不同的訪問方式,主要有兩種方式:
兩種使用方式的圖示說明如下圖:圖片來源 http://www.th7.cn/Program/java/201604/846729.shtml
垃圾回收算法
判斷一個對象是否死去,不可能再被用的算法有兩種:
可以作為GC Roots的對象有:
在Java中有四種引用強度:
系統的GC工作流程如下圖所示,總的來說,一個對象被回收可能會經過兩次標記過程,並且可能在finalize方法中拯救自己以避免被回收。
幾種典型的垃圾回收算法:
HotSpot VM中的垃圾回收算法的具體實現細節:為了結果的准確,GC在掃描時是需要凍結所有線程的。目前主流的Java虛擬采取的都是准確式GC,即系統知道每個內存位置的數據到底是一個什麼數據類型,以HotSpot為例,它采取的是一個叫做OopMap的數據結構來實現這樣的映射記錄。有了這樣的信息,虛擬機就直接知道哪些地方存放著對象的引用,從而避免了對內存挨個的檢查,加快了GC掃描的速度。程序的每條指令都可能導致引用關系或者內存數據的變化,即會導致OopMap的變化,這樣的話,如果給每個指令都生成一個對應的OopMap數據那麼是相當占用空間的,於是提出了安全點的概念(SafePoint),即只有當每個線程都運行到線程對應的安全點時才進行GC掃描,從而也只要給安全點上的指令生成OopMap即可,這樣就減少了OopMap的數量。而安全點的選取要考慮到GC頻率與系統性能的綜合影響,一般選取方法調用、循環跳轉、異常跳轉等“具有讓程序長時間運行的特征”的點。為了讓線程都跑到安全點停頓下來以進行GC掃描,有搶先式中斷和主動式中斷兩種方式。這裡又有另外一個問題,如果遇到一個比如處於Sleep狀態的線程,那麼它是不會走動的,如果它恰好不是在一個安全點Sleep,那麼意味著它永遠不會走到安全點來,所以又提出了安全區域(SafeRegion)的概念。即在這個區域內的點都是安全點。線程進入安全點之後會標志自己進入了安全區域,且必須等GC執行完了才會離開安全區域。
各個垃圾回收器:
幾條最普遍的內存分配規則: