欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JVM之內(nèi)存分配和回收機(jī)制

 更新時(shí)間:2023年05月01日 13:18:50   作者:吃貓的大魚  
本篇主要介紹JVM內(nèi)存分配和回收策略,內(nèi)容主要節(jié)選自《深入理解java虛擬機(jī)》,需要的朋友可以參考下

前言

本篇主要介紹JVM內(nèi)存分配和回收策略,內(nèi)容主要節(jié)選自《深入理解java虛擬機(jī)》。

一、內(nèi)存分配策略

1. 堆內(nèi)存模型

在這里插入圖片描述

組成:

  • 新生代 默認(rèn)占堆空間的三分之一,由于在新生代對象大多都是朝生夕死,則采用的是復(fù)制算法,在復(fù)制的期間會有頻繁的Minor GC。
  • 老年代 默認(rèn)占堆空間的三分之二,老年代對象大多都是長期存活的,則采用的是標(biāo)記算法,老年代的Major GC開銷非常大。
  • Eden 新生代分為2個(gè)區(qū) Eden和Survivor區(qū) 其中Eden區(qū)默認(rèn)占新生代十分之八的空間,對象優(yōu)先進(jìn)入Eden區(qū)。
  • Survivor 當(dāng)Eden區(qū)內(nèi)存滿了之后會進(jìn)行一次Minor GC存活對象會進(jìn)入Survivor區(qū),默認(rèn)占新生代十分之二空間, 其中它又均分為From區(qū)和To區(qū),在Survivor區(qū)的對象每熬過一次從From區(qū)到TO區(qū)則年齡+1。

大多情況下,對象在新生代Eden區(qū)中分配。當(dāng)Eden沒有足夠的空間分配對象時(shí)虛擬機(jī)會發(fā)起一次Minor GC。

2.2 大對象直接到老年代

大對象即需要大量連續(xù)內(nèi)存空間的對象(例如很長的字符串及數(shù)組)。虛擬機(jī)提供了一個(gè)-XX:PretenureSizeThreshoId參數(shù),令大于這個(gè)設(shè)置值的對象直接在老年代分配,這樣做的目的是避免在Eden區(qū)及兩個(gè)區(qū)之間發(fā)生大量的內(nèi)存復(fù)制。注意PretenureSizeThreshoId參數(shù)只對Serial和ParNew兩款收集器有效。

2.3 動態(tài)年齡判斷

為了能更好地適應(yīng)不同程序的內(nèi)存狀況,虛擬機(jī)并不是永遠(yuǎn)地要求對象的年齡必須達(dá)到了MaxTenuringThreshold才能晉升老年代,如果在Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進(jìn)人老年代,無須等到MaxTenuringThreshoId中要求的年齡。

2.4 內(nèi)存擔(dān)保機(jī)制

在發(fā)生Minor GC之前,虛擬機(jī)會先檢查Survivor空間是否夠用,如果夠用則直接進(jìn)行Minor GC。否則進(jìn)行檢查老年代最大連續(xù)可用空間是否大于新生代的總和,假如大于,那么這個(gè)時(shí)候發(fā)生Minor GC是安全的。假如不大于,那么需要判斷HandlePromotionFailure設(shè)置是否允許擔(dān)保失敗。假如允許,則繼續(xù)判定老年代最大可用的連續(xù)空間是否大于平均晉升到老年代對象的平均值,如果大于,這個(gè)時(shí)候可以發(fā)生Minor GC ,如果小于或者設(shè)置HandlePromotionFailure不允許擔(dān)保失敗,則需要做一次Full GC。通常會把HandlePromotionFailure開關(guān)打開,以減少Full GC。

2.5 長期存活對象

虛擬機(jī)給每個(gè)對象定義了一個(gè)對象年齡(Age)計(jì)數(shù)器(存在于對象頭中)。如果對象在Eden出生并經(jīng)過第一次MinorGC后仍然存活,并且能被Survivor容納的話,將被移動到Survwor空間中,并且對象年齡設(shè)為1。對象在Survivor區(qū)中每“熬過”一次MinorGC,年齡就增加1歲,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲),就將會被晉升到老年代中。對象晉升老年代的年齡閾值,可以通過參數(shù)-XX:MaxTenuringThreshoId設(shè)置。

二、對象存活

判斷對象存活一般有兩種方式: 引用計(jì)數(shù)算法和可達(dá)性分析算法。

1.引用計(jì)數(shù)算法

原理:

  1. 引用計(jì)數(shù)算法(Reference Counting)比較簡單,對每個(gè)對象保存一個(gè)整型的引用計(jì)數(shù)器屬性。用于記錄對象被引用的情況。
  2. 對于一個(gè)對象A,只要有任何一個(gè)對象引用了A,則A的引用計(jì)數(shù)器就加1;當(dāng)引用失效時(shí),引用計(jì)數(shù)器就減1。只要對象A的引用計(jì)數(shù)器的值為0,即表示對象A不可能再被使用,可進(jìn)行回收。

優(yōu)點(diǎn):

  1. 實(shí)現(xiàn)簡單,垃圾對象便于辨識;
  2. 判定效率高,回收沒有延遲性。

缺點(diǎn):

  1. 它需要單獨(dú)的字段存儲計(jì)數(shù)器,這樣的做法增加了存儲空間的開銷。
  2. 每次復(fù)制都需要更新計(jì)數(shù)器,伴隨著加法和減法操作,這增加了時(shí)間開銷。
  3. 引用計(jì)數(shù)器有一個(gè)嚴(yán)重的問題,即無法處理循環(huán)引用的情況。這是一條致命缺陷,導(dǎo)致在Java的垃圾回收器中沒有使用這類算法。

2.可達(dá)性分析算法

定義:相對于引用計(jì)數(shù)算法而言,可達(dá)性分析算法不僅同樣具備實(shí)現(xiàn)簡單和執(zhí)行高效等特點(diǎn),更重要的是該算法可以有效地解決在引用計(jì)數(shù)算法中循環(huán)引用的問題,防止內(nèi)存泄漏的發(fā)生。

原理:

  1. 可達(dá)性分析算法是以根對象集合(GCRoots)為起始點(diǎn),按照從上至下的方式搜索被根對象集合所連接的目標(biāo)對象是否可達(dá)。
  2. 使用可達(dá)性分析算法后,內(nèi)存中的存活對象都會被根對象集合直接或間接連接著,搜索所走過的路徑稱為引用鏈(Reference Chain)。
  3. 如果目標(biāo)對象沒有任何引用鏈相連,則是不可達(dá)的,就意味著該對象己經(jīng)死亡,可以標(biāo)記為垃圾對象。
  4. 在可達(dá)性分析算法中,只有能夠被根對象集合直接或者間接連接的對象才是存活對象。


在這里插入圖片描述

GC ROOT 對象:

  • 虛擬機(jī)棧中引用的對象;
    比如:各個(gè)線程被調(diào)用的方法中使用到的參數(shù)、局部變量等。
  • 本地方法棧內(nèi) JNI(通常說的本地方法)引用的對象;
  • 方法區(qū)中類靜態(tài)屬性引用的對象;
    比如:Java類的引用類型靜態(tài)變量
  • 方法區(qū)中常量引用的對象;
    比如:字符串常量池(string Table)里的引用
  • 所有被同步鎖 synchronized 持有的對象;
  • Java虛擬機(jī)內(nèi)部的引用。
    基本數(shù)據(jù)類型對應(yīng)的 Class 對象,一些常駐的異常對象(如:NullPointerException、OutOfMemoryError),系統(tǒng)類加載器。

3.再談引用

  • 強(qiáng)引用:強(qiáng)引用在代碼中普遍存在,例如Object obj=new Object() 這類的引用。只要強(qiáng)引用存在,垃圾回收器永遠(yuǎn)不會回收掉被引用的對象。
  • 軟引用:軟引用來描述一些還有用但并非必須的對象,在系統(tǒng)要發(fā)生內(nèi)存溢出之前,將會把這些對象列入回收范圍之中進(jìn)行第二次回收,如果第二次回收還沒有足夠的內(nèi)存,才會拋出內(nèi)存溢出異常。
  • 弱引用:弱引用也是用來描述必須對象的,但是它的強(qiáng)度比軟引用更弱,被弱引用關(guān)聯(lián)的對象只能生存到下一次垃圾回收發(fā)生之前。當(dāng)垃圾回收器工作時(shí),無論內(nèi)存是否足夠,都回收掉只被弱引用關(guān)聯(lián)的對象。
  • 虛引用:它是最弱的一種引用關(guān)系。它無法通過虛引用來取得一個(gè)對象實(shí)例。唯一目的就是能在這個(gè)對象被回收之前會收到一個(gè)系統(tǒng)通知。

三、內(nèi)存回收

1.堆內(nèi)存回收

是JVM所管理內(nèi)存最大的一塊,也是gc回收的主要區(qū)域。

1.1 哪些對象能回收?

堆內(nèi)存中對象存活是使用可達(dá)性分析算法來判斷,其中非存活對象由GC回收掉。這個(gè)就是虛擬機(jī)需要回收堆的對象。

1.2 如何回收?

  1. Minor GC:新生代收集,目標(biāo)只是新生代的垃圾收集;
  2. Major GC:老年代收集,目標(biāo)是老年代的垃圾收集(具體說只有CMS會有單獨(dú)收集老年代的行為);
  3. Full GC:收集整個(gè)java堆和方法區(qū)的垃圾收集。這里補(bǔ)充說明一下雖然網(wǎng)上很多說什么Full GC就是Major GC,在這里我要重申一下并不是,具體看書上描述如下:


在這里插入圖片描述

Mixed GC:收集整個(gè)新生代以及部分老年代的垃圾收集,僅G1支持。(類似于Full GC)

1.3 什么時(shí)候回收?

Minor GC觸發(fā)條件:

  1. Eden區(qū)域滿了,會觸發(fā)Minor GC;
  2. 新生對象需要分配到新生代的Eden,當(dāng)Eden區(qū)的內(nèi)存不夠時(shí)需要進(jìn)行MinorGC。

Major GC觸發(fā)條件:

  1. 老年代區(qū)域設(shè)置的閾值空間滿了,會觸發(fā)Major GC;
  2. 新對象需要分配到老年代,此時(shí)老年代設(shè)置閾值可用空間不足時(shí)觸發(fā)Major GC。

Full GC觸發(fā)條件:

  • 內(nèi)存擔(dān)保機(jī)制 ,Survivor空間不足時(shí),判斷是否允許擔(dān)保失敗,如果不允許則進(jìn)行Full GC。如果允許,并且每次晉升到老年代的對象平均大小>老年代最大可用連續(xù)內(nèi)存空間,也會進(jìn)行Full GC;
  • MinorGC后存活的對象超過了老年代剩余空間;
  • 方法區(qū)內(nèi)存不足時(shí);
  • 程序中調(diào)用了System.gc()方法,可用通過-XX:+ DisableExplicitGC來禁止調(diào)用System.gc;
  • CMS GC異常,CMS運(yùn)行期間預(yù)留的內(nèi)存無法滿足程序需要,就會出現(xiàn)一次“Concurrent Mode Failure”失敗,會觸發(fā)Full GC。

2.方法區(qū)回收

方法區(qū)主要回收廢棄的常量池和不再使用類型,但這個(gè)2類對象存活的判斷還不一樣。

2.1 常量池

同堆的對象存活類似-可達(dá)性分析法,具體請參考之前的可達(dá)性分析法。

2.2 類型數(shù)據(jù)

  • 該類索引的實(shí)例都已經(jīng)被回收;
  • 加載該類的類加載器已經(jīng)被回收;
  • 該類對應(yīng)的java.lang.class對象沒有任何地方被引用。

以上都是我簡單總結(jié),以下是書上關(guān)于方法區(qū)回收描述的內(nèi)容:


在這里插入圖片描述

其實(shí)從書上就可以看出來,關(guān)于方法區(qū)OOM問題大都是在程序中是有大量使用反射、動態(tài)代理、CGLIB等框架,如果在實(shí)際開發(fā)中遇到關(guān)于可以從以上幾個(gè)維度來定位問題。

總結(jié)

本篇所有理論知識都是摘抄于《深入理解java虛擬機(jī)》,有部分是自己簡單總結(jié),JVM內(nèi)存分配和回收是我們在分析JVM調(diào)優(yōu)和相關(guān)問題的基石,建議看完我本篇的去多看幾遍《深入理解java虛擬機(jī)》。

相關(guān)文章

  • Java 獲取兩個(gè)List的交集和差集,以及應(yīng)用場景操作

    Java 獲取兩個(gè)List的交集和差集,以及應(yīng)用場景操作

    這篇文章主要介紹了Java 獲取兩個(gè)List的交集和差集,以及應(yīng)用場景操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 如何獲取所有spring管理的bean

    如何獲取所有spring管理的bean

    這篇文章主要介紹了如何獲取所有spring管理的bean,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Sentinel中三種流控模式的使用詳解

    Sentinel中三種流控模式的使用詳解

    這篇文章主要為大家詳細(xì)介紹了Sentinel中三種流控模式(預(yù)熱模式,排隊(duì)等待模式和熱點(diǎn)規(guī)則)的使用,文中的示例代碼講解詳細(xì),感興趣的可以了解下
    2023-08-08
  • Java中HashMap的put過程詳解

    Java中HashMap的put過程詳解

    這篇文章主要介紹了Java中HashMap的put過程詳解,HashMap有4個(gè)構(gòu)造器,其他構(gòu)造器如果用戶沒有傳入initialCapacity?和loadFactor這兩個(gè)參數(shù),會使用默認(rèn)值一般如果new?HashMap()不傳值,需要的朋友可以參考下
    2023-07-07
  • Java8新特性之方法引用的實(shí)踐指南

    Java8新特性之方法引用的實(shí)踐指南

    這篇文章主要給大家介紹了關(guān)于Java8新特性之方法引用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 淺談Storm在zookeeper上的目錄結(jié)構(gòu)

    淺談Storm在zookeeper上的目錄結(jié)構(gòu)

    這篇文章主要介紹了淺談Storm在zookeeper上的目錄結(jié)構(gòu)的相關(guān)內(nèi)容,涉及storm使用zookeeper的操作以及詳細(xì)結(jié)構(gòu)圖,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • jvm類加載器基礎(chǔ)解析

    jvm類加載器基礎(chǔ)解析

    這篇文章主要介紹了jvm類加載器基礎(chǔ)解析,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • Spring Initializr中生成的mvnw有什么用

    Spring Initializr中生成的mvnw有什么用

    這篇文章主要介紹了Spring Initializr中生成的mvnw有什么用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Java Date時(shí)間類型的操作實(shí)現(xiàn)

    Java Date時(shí)間類型的操作實(shí)現(xiàn)

    本文主要介紹Java Date 日期類型,以及Calendar的怎么獲取時(shí)間,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-03-03
  • Spring 整合 MyBatis的實(shí)現(xiàn)步驟

    Spring 整合 MyBatis的實(shí)現(xiàn)步驟

    SpringMVC 本來就是 Spring 框架的一部分,這兩者無須再做整合,所以 SSM 整合的關(guān)鍵就是Spring對MyBatis的整合,三大框架整合完成后,將以 Spring 為核心,調(diào)用有關(guān)資源,高效運(yùn)作,這篇文章主要介紹了 Spring 整合 MyBatis的實(shí)現(xiàn)步驟,需要的朋友可以參考下
    2023-02-02

最新評論