從萌新的角度理解JVM內存管理

1. JVM內存管理機制

在進行Java程序設計時,通常不涉及內存的分配和內存回收的相關代碼,此處引用一句話:Java和C++之間存在一堵由內存動態分配和垃圾收集技術所圍成的高牆,牆外的人想進去,牆裏面的人想出來,我的從這兩句話中,捕獲到了兩個點java

  • java的自動內存管理機制,極大的節省了開發人員的精力,避免了易錯且複雜的內存管理設計,相對於手動的內存管理這是極大的飛躍。
  • java自動內存管理機制,其不能根據具體的場景提供最優的內存管理,其只提供普適的內存管理機制。想比於C++的手動內存管理,靈活性不夠,存在制約系統性能的瓶頸。

第二點是咱們深刻了解JVM內存管理機制的意義,經過對原理的把握,在指定的場景下設計JVM最優的內存管理策略,本文內容組織結構以下:程序員

  • JVM內存分配
  • JVM內存回收

2. JVM內存分配

ClassExample refereenceExample  = new ClassExample ();
複製代碼

上述代碼,若是粗略劃分的話,能夠劃分爲兩個過程:算法

  1. 在堆區分配對象內存
  2. 將對象內存地址賦值給對象引用 上述兩個過程基本就是內存分配中,比較重要的兩個知識點了,內存分配策略和對象引用 #####2.1 堆區佈局 對象分配在堆上這是毫無疑問的,若是在往下細分的話,那麼堆區的內存佈局仍是挺有講究的,大體能夠分爲以下佈局:
    堆內存佈局
  • 新生代:從名字可見通常,新生代區域中存放的對象通常是兩種:剛剛被new出來的對象,或者經歷內存回收次數很少的對象
  • 老年代:老年代從名字也可見通常,通常存放兩種對象: 佔用內存比較多的大對象和經歷過屢次內存回收過程的對象
  • 永久代:永久代的內存就比較固定,每一個類的class對象,通常存放在永久代當中。

上述JVM堆區中的內存佈局表明的是邏輯視圖,並非實際的物理佈局,實際上,JVM了提供多種不一樣的內存分配和回收的策略,每種策略抽閒出邏輯視圖都會有細微的差異,可是上述邏輯視圖能夠說是全部邏輯視圖的根視圖安全

2.2 內存分配通常過程

內存分配的通常過程
在圖中有幾個重要的概念,須要着重強調:

  • 對象大小閾值設定,在JVM中能夠經過設PretenureSizeThreshold這個參數,指定該閾值大小,若是待分配對象大小超過該閾值,嘗試在老年代中開闢內存空間存儲對象,不然嘗試在新生代中開闢內存空間存儲對象
  • MinorGC,這是JVM中一次內存回收過程,內存回收過程又稱垃圾回收過程,此次內存回收是由新生代中內存空間不足引發的,主要對新生代中的內存對象進行回收
  • FullGC,這也是JVM中的一次內存回收過程,此次內存回收過程是有老年代中內存空間不足形成的,主要針對全部堆區中的內存對象進行回收,包括新生代,老年代,以及永久代
  • 對象年齡,通過一次內存回收後依然存活的對象,其年齡會加1。當對象年齡超過一個指定閾值後,其由新生代轉向老年代存儲。這個對象年齡的閾值,一樣能夠經過設置JVM的MaxTenuringThreshold參數進行指定
2.3對象引用

JVM內存區域的佈局詳情中介紹了對象引用相關的內容bash

3. JVM內存回收

從程序員角度來看,內存回收的過程是透明,具體細節都對程序員屏蔽了。JVM內存區域的佈局詳情,仔細的介紹了JVM中的內存模型以及各個內存區存儲的數據類型。 佈局

JVM內存佈局
內存回收主要針對的內存區域主要是堆區和方法區,在上文中談及了MinorGC以及FullGC。MinorGC主要是針對堆區進行內存回收,FullGC除了對堆區進行回收,對方法區也進行回收,是相對重量級的回收動做。在內存回收這個章節中,主要從如下三個方面闡述: 1. 什麼樣的對象可回收? 解決方法:可達性分析 2. 如何回收內存? 解決方法:標記-清除算法,標記-複製算法,標記-整理算法等內存回收算法 3.何時回收合適? 解決方法:安全點和安全區域

3.1 可達性分析

可達性分析示意圖
在上圖中,一共有七個對象,箭頭的走向表明引用關係、對象1引用對象2,對象2引用對象3。 對象1是根節點(GCROOT),其餘的是非根節點(GCROOT)。 **可達性分析是指:不能被GCROOT節點經過引用鏈達到的節點,將被列入擬回收對象範圍。對象6和對象7就不能被任何一個GCRoot節點所引用,是目標回收對象。**JVM認爲這些對象不具有使用價值,能夠將其進行內存回收。 **根節點(GCROOT)**是上文中提出的重要概念,通常來講,以下對象可做爲根節點對象: (1)JVM虛擬機棧中引用的對象 (2)方法區中類靜態屬性引用對象 (3)方法區中類常量引用對象 (4)本機方法棧中引用對象 可達性分析是進行內存回收的斷定條件,在可達性分析以後,肯定哪些對象是回收目標。除了可達性分析以外, 引用計數法一樣可用來進行判斷內存回收目標對象,可是其沒法解決循環引用問題。主流的JVM都採用可達性分析。

3.2內存回收算法

經過可達性分析以後,將肯定哪些對象是回收目標,接着內存回收算法將執行具體的回收細節。下圖是內存區域中三個狀態,空閒內存是未使用內存,目標回收內存是可達性分析以後可回收內存,已佔內存是不須要回收內存。 性能

內存對象

  • 標記-清除算法 標記-清除算法是比較直白的內存回收算法,其直接釋放目標回收內存,沒有其餘任何附加操做。該算法執行後的結果以下:
    標記-清除算法執行後的內存圖
    標記-清除算法,邏輯簡單,易於理解,可是其有個致命的缺點就是其極易產生內存碎片,在分配大對象時,不能有足夠連續的內存空間而形成頻繁的GC。
  • 標記-複製算法 標記-複製算法是針對內存碎片問題提出的一種算法。
    image.png
    在標記-複製算法的設定中,始終有塊空白內存區域,如上圖長內存區域二。在內存回收時,將內存區域一種存活對象所有按序複製到內存區域二中後再對內存區域一中全部對象進行回收。經過這種作法能夠極大的避免內存碎片,可是空白內存區域將始終閒置,內存利用率不高。在上文中說起將堆區的內存分爲兩個surivior區以及Eden區就是採用標記-複製算法。Eden區和surivior之間大小比例分配默認是8:1:1.
  • 標記-整理算法 標記-整理算法,一樣是爲解決內存碎片提出的內存回收算法,其在標記-清楚算法的基礎上增長的整理功能,對內存對象進行拷貝移動,以保證空間內存空間連續。
    標記-整理算法回收後內存
    標記-整理算法,可以克服內存碎皮,且不須要額外內存,可是其拷貝和移動對象的時間消耗較高。該算法經常使用在老年代對象回收中。
3.3 何時回收內存合適

經過可達性分析,可知哪些對象是須要回收的對象,在這過程當中須要枚舉根節點,這是一個耗時操做,爲了保證內存回收的順利進行,必須保證引用關係的一致性,即在內存回收過程當中對象引用關係不會發生變化。只有在這些地方進行內存回收纔是安全點,所以JVM引入了安全點的概念,安全點處的對象引用關係不會改變,適合內存回收。安全區域是對安全點概念的擴充,指在這一段區域內對象引用關係具備一致性,能進行內存回收。spa

相關文章
相關標籤/搜索