淺析Java內存區及其垃圾回收機制

淺析Java內存區及其垃圾回收機制

  • Java三大內存區
  • Java堆與棧的形象描述
  • 兩種垃圾判別機制
  • 兩種垃圾回收技術
  • JIT編譯器技術簡介

Java三大內存區

Java三大內存區圖解

Java堆與棧的形象描述


Java的堆比較特殊,《Java編程思想》(第4版)裏把Java的堆(Java的堆是堆,Java的堆棧是棧)比作一個傳送帶,每分配一個新對象,它就往前移動一格。

但是其實這樣的描述不夠準確,因爲這樣的話會造成大量的空間浪費。我們可以設想,如果JVM真的像傳送帶一樣實現堆,那麼即使一個對象不在被使用,其存儲空間也不會被釋放。我們可以這樣理解Java的堆:

  • Java裏的堆是面向JVM實例的,由運行在此JVM實例上的所有線程共享的,用來存放實例對象(包括數組和new String()方式創造的字符串)的一塊內存空間。
  • Java的堆是一種動態內存分配的抽象描述,而不是一種具體的數據結構,其具體實現依賴於具體的Java虛擬機。
  • 由於Java堆的內存管理效率很高,我們可以把Java的堆抽象成一個優化的棧(只有GC能彈出數據的棧)。
    C++的堆無法抽象成棧主要是因爲其沒有獨立於用戶程序的垃圾回收機制,每一塊分配出去的存儲實例對象的內存都要由其自身管理(包括銷燬)。這也就是說難以實現對C++堆的整體內存再分配,所以如果把C++的結構抽象爲棧這一數據結構的話,那麼很難保證C++的堆不會滿。而Java則不同了,其具有一個自動的,面向於JVM的垃圾回收機制(相當於MySQL 裏的OPTIMIZE TABLE對錶的作用);通過GC,那麼我們可以利用虛擬機自動實現棧中空間的重新整理,並對Java棧中這些實例對象的引用變量的值進行自動更新(這也是Java引用與c的指針的區別之一)。

  • 同一個調用棧裏存放Java方法的棧幀與native方法的棧幀
  • 棧中存放一些基本類型的變量和對象的引用變量。當在一段代碼塊定義一個變量時,Java就在棧中爲這個變量分配內存空間,當超過變量的作用域後,Java會自動釋放掉爲該變量所分配的內存空間,該內存空間可以立即被另作他用。
  • 棧中的變量可以被多個引用變量連接。比如我們給一個int型變量i賦值1的時候,JVM會在棧中尋找是否有一個值爲1的整數,有的話就把這個基本類型內存空間與i關聯。與對象引用不同的是,把一個新值賦值給基本變量時,JVM通過改變引用指向的內存空間來改變其值。就是說,如果給i賦值2,那麼JVM先查找棧中是否有2,有的話修正引用,而非存儲1的那個內存單元;沒有的話就把2壓棧。
  • 下面說一下兩種垃圾判別機制

    引用計數 

    特點 描述
    發生時間 程序生命週期。
    方式 每個對象都有一個引用計數器,當引用離開作用域或被置爲null時減一,當對象被連接到一個新引用變量上時,計數器加1。當對象引用計數器爲0時,釋放對象。
    優點 思想簡單。
    缺點 當出現循環引用的情況時,無法及時回收相關對象;且JVM判斷循環引用的開銷較大。

    可以使用冒號來定義對齊方式:

    追溯堆棧或靜態存儲區活引用法
    這種方法,就是從堆棧和靜態存儲區開始,遍歷所有引用,對於發現的每個對象,再遍歷此對象所包含的所有引用,反覆進行。類似於圖的遍歷,在這個圖裏的所有節點(對象)都是活的,剩餘的對象就可以被判別爲回收了。而且,因爲“引用計數”法中的交互引用對象幾乎不會在堆棧和靜態存儲區中(而是隨着對象存儲在堆中)出現,所以幾乎完全避免了這個現象。

    兩種垃圾回收技術

    總括 《Java編程思想》(第四版中文版)關於JVM垃圾回收技術的概括:
    自適應的、分代的、停止-複製、標記-清掃的。

    我們先來介紹下停止-複製技術的步驟:
    1. 暫停程序運行(這點看出其不屬於後臺回收模式);
    2. 將堆中存活的對象從當前堆(或者是當前堆中的塊),複製到另一個可用堆(或者是當前堆中可用的塊)中;
    3. 原來的堆(塊)中就只剩下垃圾,交給GC處理。
    注意:

  • 2中的實現方式依賴於具體的實現;
  • 當原來存活的對象被複制到新堆後,就又是一個接着一個緊密排列的了;
  • 當對象被複制時,其靜態存儲區和棧中的引用變量會被JVM修正,但是堆中對象裏的引用會延遲到被遍歷時纔會修正(相當於有一張邏輯上存儲新舊地址映射關係的表);
  • 當出現只有少量垃圾的情況時,每次都採用停止-複製模式的話,開銷太大;
  • 於是,引出了標記-清掃方式
    1. JVM從靜態存儲區和棧開始遍歷所有引用,標記其中所有獲得引用;
    2. 之後,標記工作結束時,JVM回收沒有被標記的對象。但是,不發生對象複製,所以會節省空間和時間,但並沒有起到使對象緊湊排列的作用。

    自適應
    JVM會監視垃圾回收效率,選擇並切換這兩種方式進行垃圾回收。

    分代
    Java虛擬機的分代比較複雜,可以參考這篇文章

    JIT

    可以參考這篇文章,哈哈!偷個懶,這兩個東西要說的太多了!

    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章