天天看點

性能優化|一張圖帶你了解JVM是如何進行記憶體配置設定

對象優先在新生代配置設定

  • 如果對象能夠在eden區配置設定,那麼就直接在eden區配置設定
  • 如果eden區域大小不夠新對象存儲的話,則會觸發一次minor gc,
  • 如果minor gc後發現對象也無法在s區配置設定,則會直接在老年代中配置設定
  • 如果老年代也無法存儲,則會觸發full gc

什麼情況下,對象會直接在老年代中配置設定?

  • 大對象會直接進入老年代

    什麼叫做大對象呢,這個是由我們配置的參數決定的

    -XX:PretenureSizeThreshold=xxx

    如果新配置設定的對象超過這個值,就會直接在老年代中配置設定對象,這樣做的目的是減小大對象來回複制帶來的gc 時間損耗,需要注意的是這個參數隻在serial和parNew兩種收集器下生效

  • 長期存活的對象會直接進入老年代
  • 如何判對對象是長期存活的?

    虛拟機會給每個對象的頭部配置設定一個字段,記錄對象的年齡,年齡預設為1,在經曆一次minor gc之後,如果對象還存活,則将年齡加1;

  • 如果對象的年齡達到了 -XX:MaxTenuringThreshold參數配置的值,預設為15,則會直接進入老年代
  • 動态年齡判斷,決定是否進入老年代

    動态年齡判斷是在minor gc之後出發的。

    在每次minor gc之後,會按照年齡大小進行排序,從年齡小的開始累加記憶體空間,如果累加到年齡為10的對象的時候,記憶體空間已經超過了s區的50%,這個時候就會把大于年齡10的存活對象全部移動老年代中;

  • minor gc之後,s區放不下,會直接移動到老年代中

什麼叫空間配置設定擔保機制?

jvm在每次minor gc之前,都會計算老年代的剩餘可用空間,如果可用空間小于年輕代裡面所有對象之和,如果沒有配置擔保參數(“-XX:-HandlePromotionFailure),這個時候就會直接執行full gc,如果配置了擔保參數,就不會立即發生full gc,這個時候需要判斷老年代可用空間是否大于之前每次minor gc後移動到老年代的平均大小,如果大于,則還是執行minor gc,否則執行 full gc ,流程圖如下:

性能優化|一張圖帶你了解JVM是如何進行記憶體配置設定

如何判斷對象是否被回收

  • 引用計數法

    給對象中添加一個引用計數器,每當有一個地方引用它,計數器就加1;當引用 失效,計數器就減1;任何時候計數器為0的對象就是不可能再被使用的。

    這個方法實作簡單,效率高,但是目前主流的虛拟機中并沒有選擇這個算法來管 理記憶體,其最主要的原因是它很難解決對象之間互相循環引用的問題

  • 可達性分析算法

    這個算法的基本思想就是通過一系列的稱為 “GC Roots” 的對象作為起點, 從這些節點開始向下搜尋,找到的對象都标記為非垃圾對象,其餘未标記的對象 都是垃圾對象 GC Roots根節點:線程棧的本地變量、靜态變量、本地方法棧的變量等等