程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java內存以及GC,Java內存GC

Java內存以及GC,Java內存GC

編輯:JAVA綜合教程

Java內存以及GC,Java內存GC


《深入理解Java虛擬機》第二三章摘要

Java內存區域與內存溢出

Java虛擬機中的內存分配圖

各個區域的特性總結如下表:

   

補充說明:

  • 當多線程情形下,可能多個線程要在堆上分配內存,那麼可能出現內存分配的同步問題,解決方案有兩個,一個就是同步內存分配動作;另一個就是采用TLAB,即在Java堆中針對每個線程先預先分配一小塊線程私有的本地線程分配緩沖。這樣當線程需要分配內存時就在自己的TLAB上進行,從而避免同步的開銷。但是當TLAB分配滿重新分配TLAB時仍需要同步;
  • 判斷一個類是否屬於無用的類,“可以”被回收的條件為:1 該類所有的實例都已經被回收;2 加載該類的ClassLoader已經被回收; 3 該類對於的java.lang.Class對象沒有在任何地方被引用。注意,只是可以,而不是要被回收。

內存分配方式:虛擬機使用哪種方式由內存是否規整決定,而內存是否規整則由回收算法決定。

對象在HotSpot虛擬機中的內存布局如下表所示:

  

在Java規范中,對於reference類型只規定了一個指向對象的引用,但沒有規定通過何種方式去訪問引用的數據。因此對於不同的虛擬機也有不同的訪問方式,主要有兩種方式:

兩種使用方式的圖示說明如下圖:圖片來源 http://www.th7.cn/Program/java/201604/846729.shtml

 

垃圾回收算法

判斷一個對象是否死去,不可能再被用的算法有兩種:

可以作為GC Roots的對象有:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象
  • 方法區中類靜態屬性引用的對象
  • 方法區中常量引用的對象
  • Native方法中引用的對象

在Java中有四種引用強度

  • 強引用:強引用永遠不會被垃圾回收器回收
  • 軟引用:系統提供SoftReference類來表示,表示還有但是非必須的對象。其回收時機在於把若引用對象回收完之後內存還不夠,則回收此類引用,若還不夠,則OOM
  • 弱引用:通過WeakReference類來表示,此類引用只能生存到下一次垃圾回收之前。當垃圾收集器工作時,無論當前內存是否足夠都會回收掉只被弱引用關聯的對象。即只要發生了GC,弱引用必定被回收。其與已經沒有到GC Roots的引用鏈的區別在於:還是可以通過弱引用來訪問這些對象的,但是沒有引用鏈的對象則永遠不可能再被訪問到了。
  • 虛引用:通過PhantomReference來實現,其對對象的生存時間沒有任何影響,其存在的意義在於能在被虛引用引用的對象被回收的時候收到一個系統通知。

系統的GC工作流程如下圖所示,總的來說,一個對象被回收可能會經過兩次標記過程,並且可能在finalize方法中拯救自己以避免被回收。

    

    

 幾種典型的垃圾回收算法

 

HotSpot VM中的垃圾回收算法的具體實現細節:為了結果的准確,GC在掃描時是需要凍結所有線程的。目前主流的Java虛擬采取的都是准確式GC,即系統知道每個內存位置的數據到底是一個什麼數據類型,以HotSpot為例,它采取的是一個叫做OopMap的數據結構來實現這樣的映射記錄。有了這樣的信息,虛擬機就直接知道哪些地方存放著對象的引用,從而避免了對內存挨個的檢查,加快了GC掃描的速度。程序的每條指令都可能導致引用關系或者內存數據的變化,即會導致OopMap的變化,這樣的話,如果給每個指令都生成一個對應的OopMap數據那麼是相當占用空間的,於是提出了安全點的概念(SafePoint),即只有當每個線程都運行到線程對應的安全點時才進行GC掃描,從而也只要給安全點上的指令生成OopMap即可,這樣就減少了OopMap的數量。而安全點的選取要考慮到GC頻率與系統性能的綜合影響,一般選取方法調用、循環跳轉、異常跳轉等“具有讓程序長時間運行的特征”的點。為了讓線程都跑到安全點停頓下來以進行GC掃描,有搶先式中斷和主動式中斷兩種方式。這裡又有另外一個問題,如果遇到一個比如處於Sleep狀態的線程,那麼它是不會走動的,如果它恰好不是在一個安全點Sleep,那麼意味著它永遠不會走到安全點來,所以又提出了安全區域(SafeRegion)的概念。即在這個區域內的點都是安全點。線程進入安全點之後會標志自己進入了安全區域,且必須等GC執行完了才會離開安全區域。

 

 各個垃圾回收器

 

幾條最普遍的內存分配規則

  • 對象優先分配在Eden區:當Eden區內存不夠的時候,系統將發起一次速度較快的Minor GC
  • 大對象直接進入老年代:對於較長的數組以及字符串等大對象,直接把他們分配在老年代區。因此,對於那種生命周期較短的大對象,很容引起GC,應該盡量避免。
  • 長期存活的對象將進入老年代:一個若在Survivor區經歷多次Minor GC還存活,默認15次,則將被移入老年代區。
  • 動態對象年齡判定:此條是結合上一條的,要是Survivor中相同年齡的所有對象的大小和超過Survivor的一半,那麼年齡大於或者等於該年齡的對象將移入老年代區,無需等到15次
  • 空間分配擔保:針對新生代的復制收集算法。若參數容許,當執行Minor GC之後,若存活的對象無法全部放在Survivor中,那麼將把多的對象直接放入老年代區。若老年代也沒足夠的空間,那麼將發生Full GC以獲得更多空間

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved