JVM內存管理—內存回收—哪些內存需要回收?

哪些區域需要回收

運行時內存分為5個區域:程序計數器、虛擬機棧、本地方法棧、堆、方法區,這些區域是如何回收的?

1-程序計數器、虛擬機棧、本地方法棧

這3個區域是隨著線程而生,隨著線程而滅,棧中的棧幀數據隨著方法的調用到結束有條不紊的進行著入棧出棧,每一個棧幀中分配多少內部基本上在類結構確定下來(類加載)就已知了。內存分配和回收具有確定性,隨著方法的結束或者線程的結束后,內存自然就會被回收了。

2- java堆和方法區

一個接口中的多個實現類需要的內存可能不一樣,一個方法的多個分支需要的內存也不一樣,我們只有在程序處于執行期間才能知道會創建哪些對象,對這部分的內存分配和回收是動態的,垃圾回收主要關注的是這部分的內存

判斷對象是“生”是“死”?

引用計數算法

java虛擬機沒有采用引用計數算法來判斷對象是否生存,主要考慮的是它很難解決對象之間的相互循環引用的問題。

可達性分析算法(Reachablity Analysis)

基本思路是:從每一個GC Roots出發找到它所有可達的對象,走過的路徑成為引用鏈,被引用鏈串起來的就是存活對象;其他的雖然存在引用關系,但是GC Roots不可達的,判定為可回收對象。、
GC Roots :可作為的對象包含以下幾種:

  1. 虛擬機棧(棧幀中本地變量表)中引用的對象
  2. 方法區中類靜態屬性引用的對象
  3. 方法區常量引用的對象
  4. 本地方法棧中JNI(Native Method)引用的對象

引用與緩存

為了更細致的管理對象的內存,對象引用進行了擴展,分為:強引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference,也叫幽靈引用)

強引用
  • Object obj = new Object(); 這種通過關鍵字new出來的對象就屬于強引用,普遍存在的,只要這種引用還關聯著對象,就不會被垃圾回收器回收。
  • **內存空間不夠時,不會進行垃圾回收,而是直接拋出內存溢出異常 **
軟引用

用來描述有用但是并不必需的對象,在系統將要發生內存溢出異常之前,JVM將會把這些對象標記成垃圾數據,并對這些標記的數據進行二次回收,若回收后還是沒有足夠的內存分配,才會拋出內存溢出的異常。 用法: 用來實現內存敏感的緩存

import java.lang.ref.SoftReference;
class ReferenceTest{
    Object obj = new Object();//強引用
    SoftReference<Object> sr = new SoftReference<Object>(obj);//關聯軟引用
    // 取消強引用,只保留軟引用
    obj=null;
    pass(...);
    //通用的處理,以及softreference的復用模式
    if(sr.get() != null){
        Obeject getRef = sr.get();
        use(getRef);
    }else{
        Object newObj = new Object();
        sr = new SoftReference(newObj);//重建軟引用
    }
}
  • 注意
    1.在虛擬機內存空間足夠大的時候是不會發生內存回收的,而且GC的優先級最低,只有所有線程都停止時才有可能執行GC(即使使用System.gc()也只是告訴JVM這是一個執行GC的好時機,但是實際上JVM會自己決斷是否達到了這個條件,比如沒有線程正在執行,這是GC這個守護線程就會執行),因為GC有一定的代價。所以與軟引用關聯的對象在內存充足時是不會發生的,只有處于內存溢出的邊緣才會發生回收操作。
    2.雖然與軟引用關聯的對象可能會被收回,但保存這個軟引用關系的SoftReference變量并不一定會被回收,所以出現了ReferenceQueue來管理這些變量。
弱引用
  • 弱引用描述的是非必需的對象:被弱引用關聯的對象只能生存到下一次GC回收發生之前,當GC工作時,無論當前空間是否足夠,都會回收只被弱引用關聯的對象
  • 用法:一般會和ReferenceQueue進行關聯
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
public class WeakReferenceTest{
    public static void main(Stting[] args) throws Exception{
        Object obj = new Object();
        //ReferenceQueue的作用:
        //當弱引用關聯的對象被標記為垃圾,準備回收時,
        //會自動把保存弱引用的對象WeakReference放到ReferenceQueue中,等待被處理
        //主要目的是:引用關聯的對象被回收了,但存儲引用的對象沒有及時回收會造成
        //內存膨脹
        ReferenceQueue<Object> rf = new ReferenceQueue<Object>();
        WeakReference<Object> wf = new WeakReference<Object>(obj,rf);
        WeakReference<Object> wf_q = null;
                // poll方法,刪除隊尾引用并返回
        while(wf_q = rf.poll()!= null){
            // do something for remove reference
        }
    }
}
虛引用
  • 最弱的一種引用關系,無法通過虛引用來獲取對象的實例
  • 用途:僅僅是在這個對象被回收時收到一個系統的通知。
總結

對于軟引用和弱引用,被GC標記為垃圾準備回收時會清除對應的引用,即get方法返回null,然后放入綁定的引用隊列中,理論上此時沒有真正被回收,只是沒有辦法在訪問到;但是對于虛引用則是在發生回收時放入隊列,也是唯一一種確認對象被回收而加入隊列的引用,可以利用這一特性做一些有趣的事。


finalize()越獄

通過一條到墻外的地下通道(finalize)、一列快速列車(F-Queue)的驚險越獄大片

  • 可達性分析發現這個對象沒有到GC Roots的引用鏈(快到砍頭的時候了),進行第一次標記如果對象沒有覆蓋Object的finalize方法,或者已經執行過了一次finalize方法,則這個對象的finalize不會執行,等待下一次GC被回收(蠢蛋和倒霉蛋的組合,一個不知道這個秘密通道,一個越獄失敗被抓了回來成為重點照顧對象,沒日沒夜的毒打,只能等死了)
  • 如果覆蓋了finalize方法但還沒有執行(已經踩好點了,還在做最后的精密計劃,天一黑,就行動),將這個對象放到F-Queue中等待執行finalize方法(通過地下秘密通道到達獄外,此時列車也到了,正在排隊刷卡上車...)
  • 以低優先級執行F-Queue中對象的finalize方法,進行第二次標記,如果finalize中將自己對象的引用與外面的引用鏈上的對象建立了鏈接,則將其移出F-Queue,成功逃脫回收(滴,學生卡,上車落座,系好安全帶,老司機要飆車了),如果沒有建立與引用鏈的鏈接,則等待下一次GC被回收(滴,余額不足,請及時充值,司機說窮鬼,沒錢還想做快速列車。哎哎哎~,老司機帶帶我呀,帶帶我呀,帶我呀,我呀,呀...曾經的秋名山車神遺棄在角落。)

進行了兩次標記:第一次標記是篩選有哪些finalize方法是需要執行的;第二次標記是哪些finalize方法關聯了引用鏈,將其移出隊列。

public class SaveSelfTest {
    public static Scofield BreakAway= null;//逃生專列
    public static void main(String[] args) throws Exception{
        Scofield michael = new Scofield();
        michael.sayHi();
        
        //第一次逃脫,成功
        michael = null;//置為null,觸發回收的條件
        System.gc();
        Thread.sleep(200);
        
        if(BreakAway != null){
            BreakAway.sayHi();
        }else{
            util.print("ScoField:Please save me,I'll dead next morning!");
        }
        
        //第二次逃脫,失敗,finalize函數只能最多被執行一次
        BreakAway = null;
        System.gc();
        Thread.sleep(200);
        
        if(BreakAway != null){
            BreakAway.sayHi();
        }else{
            util.print("ScoField:Please save me,I'll dead next morning!");
        }
        
        System.exit(0);
    }

}
class Scofield{
    public void sayHi(){
        util.print("Hi, I'm Michael ScoField!");
    }
    @Override
    protected void  finalize() throws Throwable{
        super.finalize();//Object
        util.print("Scofield gets on car!");
        SaveSelfTest.BreakAway = this;//關聯引用鏈
    }
}
class util{
    public static void print(String str){
        System.out.println(str);
    }
}
/* Output
Hi, I'm Michael ScoField!
Scofield gets on car!
Hi, I'm Michael ScoField!
ScoField:Please save me,I'll dead next morning!
*/

參考鏈接
http://www.cnblogs.com/jiangyi-uestc/p/5679331.html
http://www.importnew.com/14115.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容