成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

講講 JVM 的內存管理『非專業』

云計算 虛擬化
在 JDK 1.7 及以前,HotSpot 虛擬機中的方法區是用永久代實現的,永久代中存放的為一些 Class 的信息、常量、靜態變量等數據。

[[399153]]

 jvm 內存布局

一類是每個線程所獨享的:

  1. PC Register:也稱為程序計數器, 記錄每個線程當前執行的指令信息(eg:當前執行到哪一條指令,下一條該取哪條指令)
  2. JVM Stack:也稱為虛擬機棧,記錄每個棧幀(Frame)中的局部變量、方法返回地址等。線程中每次有方法調用時,會創建Frame,方法調用結束時Frame銷毀。
  3. Native Method Stack: 本地(原生)方法棧,顧名思義就是調用操作系統原生本地方法時,所需要的內存區域。

上述3類區域,生命周期與Thread相同,即:線程創建時,相應的內存區創建,線程銷毀時,釋放相應內存。

  • Heap:即鼎鼎大名的堆內存區,也是GC垃圾回收的主站場,用于存放類的實例對象及Arrays實例等。

注:Heap被所有線程共享,如果嚴格意義上摳字眼的話,也不完正確,事實上,由于TLAB的存在,為了防止并發對象分配時,多個對象分配到同1塊內存,heap中的TLAB區域,在分配時,是被線程獨占寫入的。

  • Method Area:方法區,主要存放類結構、類成員定義,static靜態成員等。
  • Runtime Constant Pool:運行時常量池,比如:字符串,int -128~127范圍的值等,它是Method Area中的一部分。

Heap、Method Area 都是在虛擬機啟動時創建,虛擬機退出時釋放

哪些內存區域需要 GC

thread獨享的區域:PC Regiester、JVM Stack、Native Method Stack,其生命周期都與線程相同(即:與線程共生死),所以無需GC。線程共享的Heap區、Method Area則是GC關注的重點對象。

引用類型

強引用:被強引用關聯的對象不會被回收。

軟引用:被軟引用關聯的對象只有在內存不夠的情況下才會被回收。

弱引用:被弱引用關聯的對象一定會被回收,也就是說它只能存活到下一次垃圾回收發生之前。

虛引用:為一個對象設置虛引用的唯一目的是能在這個對象被回收時收到一個系統通知。

Minor GC 和 Full GC

Minor GC:回收新生代,因為新生代對象存活時間很短,因此 Minor GC 會頻繁執行,執行的速度一般也會比較快。

Minor GC,其觸發條件非常簡單,當 Eden 空間滿時,就將觸發一次 Minor GC。

Full GC:回收老年代和新生代,老年代對象其存活時間長,因此 Full GC 很少執行,執行速度會比 Minor GC 慢很多。

FULL GC 的觸發條件有以下幾個:

「調用 System.gc()」

只是建議虛擬機執行 Full GC,但是虛擬機不一定真正去執行。不建議使用這種方式,而是讓虛擬機管理內存。

「老年代空間不足」

老年代空間不足的常見場景為前文所講的大對象直接進入老年代、長期存活的對象進入老年代等。

為了避免以上原因引起的 Full GC,1.應當盡量不要創建過大的對象以及數組。2.除此之外,可以通過 -Xmn 虛擬機參數調大新生代的大小,讓對象盡量在新生代被回收掉,不進入老年代。3.還可以通過 -XX:MaxTenuringThreshold 調大對象進入老年代的年齡,讓對象在新生代多存活一段時間。

「空間分配擔保失敗」

使用復制算法的 Minor GC 需要老年代的內存空間作擔保,如果擔保失敗會執行一次 Full GC。

「JDK 1.7 及以前的永久代空間不足」

在 JDK 1.7 及以前,HotSpot 虛擬機中的方法區是用永久代實現的,永久代中存放的為一些 Class 的信息、常量、靜態變量等數據。

當系統中要加載的類、反射的類和調用的方法較多時,永久代可能會被占滿,在未配置為采用 CMS GC 的情況下也會執行 Full GC。如果經過 Full GC 仍然回收不了,那么虛擬機會拋出 java.lang.OutOfMemoryError。

為避免以上原因引起的 Full GC,可采用的方法為增大永久代空間或轉為使用 CMS GC。

「Concurrent Mode Failure」

執行 CMS GC 的過程中同時有對象要放入老年代,而此時老年代空間不足(可能是 GC 過程中浮動垃圾過多導致暫時性的空間不足),便會報 Concurrent Mode Failure 錯誤,并觸發 Full GC。

如何判斷對象是垃圾

引用計數算法

在兩個對象出現循環引用的情況下,此時引用計數器永遠不為 0,導致無法對它們進行回收。正是因為循環引用的存在,因此 Java 虛擬機不使用引用計數算法。

  • 可達性分析算法

以 GC Roots 為起始點進行搜索,可達的對象都是存活的,不可達的對象可被回收。

Java 虛擬機使用該算法來判斷對象是否可被回收,GC Roots 一般包含以下內容:

  • 虛擬機棧中局部變量表中引用的對象
  • 本地方法棧中 JNI 中引用的對象
  • 方法區中類靜態屬性引用的對象
  • 方法區中的常量引用的對象

除了對象回收之外,還可能會有類的卸載

方法區主要存放永久代對象,而永久代對象的回收率比新生代低很多,所以在方法區上進行回收性價比不高。方法區的回收主要是對常量池的回收和對類的卸載。

為了避免內存溢出,在大量使用反射和動態代理的場景都需要虛擬機具備類卸載功能。類的卸載條件很多,需要滿足以下三個條件,并且滿足了條件也不一定會被卸載:

  • 該類所有的實例都已經被回收,此時堆中不存在該類的任何實例。
  • 加載該類的 ClassLoader 已經被回收。
  • 該類對應的 Class 對象沒有在任何地方被引用,也就無法在任何地方通過反射訪問該類方法。

finalize()

  • 類似 C++ 的析構函數,用于關閉外部資源。但是 try-finally 等方式可以做得更好,并且該方法運行代價很高,不確定性大,無法保證各個對象的調用順序,因此最好不要使用。
  • 當一個對象可被回收時,如果需要執行該對象的 finalize() 方法,那么就有可能在該方法中讓對象重新被引用,從而實現自救。自救只能進行一次,如果回收的對象之前調用了 finalize() 方法自救,后面回收時不會再調用該方法。

常用的 GC 算法

「標記清除法」:在標記階段,程序會檢查每個對象是否為活動對象,如果是活動對象,則程序會在對象頭部打上標記。

在清除階段,會進行對象回收并取消標志位,另外,還會判斷回收后的分塊與前一個空閑分塊是否連續,若連續,會合并這兩個分塊。回收對象就是把對象作為分塊,連接到被稱為 “空閑鏈表” 的單向鏈表,之后進行分配時只需要遍歷這個空閑鏈表,就可以找到分塊。

優缺點:

  • 標記和清除過程效率都不高;
  • 會產生大量不連續的內存碎片,導致無法給大對象分配內存。

「標記復制法」:思路也很簡單,將內存對半分,總是保留一塊空著(上圖中的右側),將左側存活的對象(淺灰色區域)復制到右側,然后左側全部清空。

優缺點:

  • 避免了內存碎片問題。
  • 內存浪費很嚴重,相當于只能使用50%的內存。

現在的商業虛擬機都采用這種收集算法回收新生代,但是并不是劃分為大小相等的兩塊,而是一塊較大的 Eden 空間和兩塊較小的 Survivor 空間,每次使用 Eden 和其中一塊 Survivor。在回收時,將 Eden 和 Survivor 中還存活著的對象全部復制到另一塊 Survivor 上,最后清理 Eden 和使用過的那一塊 Survivor。

HotSpot 虛擬機的 Eden 和 Survivor 大小比例默認為 8:1,保證了內存的利用率達到 90%。如果每次回收有多于 10% 的對象存活,那么一塊 Survivor 就不夠用了,此時需要依賴于老年代進行空間分配擔保,也就是借用老年代的空間存儲放不下的對象。

「標記-整理(也稱標記-壓縮)法」:避免了上述二種算法的缺點,將垃圾對象清理掉后,同時將剩下的存活對象進行整理挪動(類似于windows的磁盤碎片整理),保證它們占用的空間連續,這樣就避免了內存碎片問題,但是整理過程也會降低GC的效率.

「generation-collect 分代收集算法」:經過大量實際分析,發現內存中的對象,大致可以分為二類:有些生命周期很短,比如一些局部變量/臨時對象,而另一些則會存活很久(典型的,比如websocket長連接中的connection對象)。基本思想是將內存分成了三大塊:年青代(Young Genaration),老年代(Old Generation),永久代(Permanent Generation),其中Young Genaration更是又細為分eden,S0, S1三個區。

剛開始時,對象分配在eden區,s0及s1區,幾乎是空著的。當eden區放不下時,就會發生minor GC(也被稱為young GC),第1步當然是要先標識出不可達垃圾對象,然后講可達對象移到 s0 區。之后當 eden 區又滿了之后,s0 和 eden 區的可達對象將會都移到 s1 區。之后 s0 和 s1 區的對象會相互移來移去,每移動 1 次,他們的年齡會 +1。所以當它們的年齡到達一定區域之后,將會移到老年代。如果老年代也滿了,那么將會移到永久代。

  • 新生代使用:復制算法
  • 老年代使用:標記 - 清除 或者 標記 - 整理 算法

垃圾收集器

https://www.jianshu.com/p/b572f69a1b93

**新生代垃圾收集器有Serial、ParNew、Parallel Scavenge,G1,屬于老年代的垃圾收集器有CMS、Serial Old、Parallel Old和G1。**其中的G1是一種既可以對新生代對象也可以對老年代對象進行回收的垃圾收集器。然而,在所有的垃圾收集器中,并沒有一種普遍使用的垃圾收集器。在不同的場景下,每種垃圾收集器有各自的優勢,如下圖:

  • 「Serial收集器」

**單線程垃圾收集器,**這就意味著在其進行垃圾收集的時候需要暫停其他的線程。

收集過程:暫停所有線程 算法:復制算法 優點:簡單高效,擁有很高的單線程收集效率 應用:Client模式下的默認新生代收集器

  • 「ParNew收集器」

理解為**Serial收集器的多線程版本,由于存在線程切換的開銷,**ParNew在單CPU的環境中比不上Serial(ParNew收集線程數與CPU的數量相同, 因此在CPU數量過大的環境中, 可用-XX:ParallelGCThreads參數控制GC線程數)。

收集過程:暫停所有線程 算法:復制算法 優點:在CPU多的情況下,擁有比Serial更好的效果。單CPU環境下Serial效果更好 應用:許多運行在Server模式下的虛擬機中首選的新生代收集器

  • 「Parallel Scavenge 收集器」

類似ParNew收集器,**Parallel收集器更關注系統的吞吐量。**區別在于Parallel Scavenge收集器更關注可控制的吞吐量(「吞吐量 = 運行用戶代碼的時間/(運行用戶代碼的時間+垃圾收集時間)」)。吞吐量越大,意味著垃圾收集的時間越短,則用戶代碼則可以充分利用CPU資源,盡快完成程序的運算任務。

-XX:MaxGCPauseMillis 控制最大的垃圾收集停頓時間,-XX:GCRatio 直接設置吞吐量的大小。

-XX:+UseAdaptiveSizePocily 來動態調整停頓時間或者最大的吞吐量,這種方式稱為GC自適應調節策略,這點是ParNew收集器所沒有的。

  • 「Serial Old收集器」

「Serial Old收集器是Serial收集器的老年代版本」,也是一個單線程收集器,采用“「標記-整理算法」”進行回收。其運行過程與Serial收集器一樣。

  • 「Parallel Old收集器」

Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多線程和“「標記-整理」”算法進行垃圾回收。

通常與Parallel Scavenge收集器配合使用,“吞吐量優先”收集器是這個組合的特點,在注重吞吐量和CPU資源敏感的場合,都可以使用這個組合。

  • 「CMS 收集器」

CMS(Concurrent Mark Sweep)收集器是一種「以獲取最短回收停頓時間為目標的收集器」。目前很大一部分的Java應用都集中在互聯網站或B/S系統的服務端上,這類應用尤其重視服務的響應速度,希望系統停頓時間最短,以給用戶帶來較好的體驗。

「基于“標記-清除”算法實現的」,它的運作過程相對于前面幾種收集器來說要更復雜一些,整個過程分為4個步驟,包括:

其中**初始標記、重新標記這兩個步驟仍然需要“Stop The World”。**初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快,并發標記階段就是進行GC Roots Tracing的過程,而重新標記階段則是為了修正并發標記期間,因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比并發標記的時間短。

「由于整個過程中耗時最長的并發標記和并發清除過程中,收集器線程都可以與用戶線程一起工作,所以總體上來說,CMS收集器的內存回收過程是與用戶線程一起并發地執行。」

優缺點:

  • 并發收集、低停頓
  • 產生大量空間碎片、并發階段會降低吞吐量
  • 初始標記(CMS initial mark)
  • 并發標記(CMS concurrent mark)
  • 重新標記(CMS remark)
  • 并發清除(CMS concurrent sweep)

「G1 收集器」(整個Java堆:包括新生代和老年代)

G1 的特點是:采用并發與并行、空間整合(整體上類似標記-整理方法,不會產生內存碎片)、分代收集、「可預測的停頓」(比CMS更先進的地方在于能讓使用者明確指定一個長度為M毫秒的時間片段內,消耗在垃圾收集上的時間不得超過N毫秒)。

G1收集器將Java堆劃分為多個大小相等的Region(獨立區域),新生代與老年代都是一部分Region的集合,G1的收集范圍則是這一個個Region。

整個工作流程:初始標記、并發標記、最終標記、篩選回收。初始標記階段僅僅只是標記一下GC Roots能夠直接關聯的對象,并且修改TAMS(Next Top at Mark Start)的值,讓下一階段的用戶程序并發運行的時候,能在正確可用的Region中創建對象,這個階段需要暫停線程。并發標記階段從GC Roots進行可達性分析,找出存活的對象,這個階段是與用戶線程并發執行的。最終標記階段則是修正在并發標記階段因為用戶程序的并發執行而導致標記產生變動的那一部分記錄,這部分記錄被保存在Remembered Set Logs中,最終標記階段再把Logs中的記錄合并到Remembered Set中,這個階段是并行執行的,仍然需要暫停用戶線程。最后在篩選階段首先對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間制定回收計劃。

內存分配策略

  • 對象優先在 Eden 分配

大多數情況下,對象在新生代 Eden 上分配,當 Eden 空間不夠時,發起 Minor GC。

  • 大對象直接進入老年代

大對象是指需要連續內存空間的對象,最典型的大對象是那種很長的字符串以及數組。

經常出現大對象會提前觸發垃圾收集以獲取足夠的連續空間分配給大對象。

-XX:PretenureSizeThreshold,大于此值的對象直接在老年代分配,避免在 Eden 和 Survivor 之間的大量內存復制。

  • 長期存活的對象進入老年代

為對象定義年齡計數器,對象在 Eden 出生并經過 Minor GC 依然存活,將移動到 Survivor 中,年齡就增加 1 歲,增加到一定年齡則移動到老年代中。

-XX:MaxTenuringThreshold 用來定義年齡的閾值。

  • 動態對象年齡判斷

虛擬機并不是永遠要求對象的年齡必須達到 MaxTenuringThreshold 才能晉升老年代,如果在 Survivor 中相同年齡所有對象大小的總和大于 Survivor 空間的一半,則年齡大于或等于該年齡的對象可以直接進入老年代,無需等到 MaxTenuringThreshold 中要求的年齡。

  • 空間分配擔保

在發生 Minor GC 之前,虛擬機先檢查老年代最大可用的連續空間是否大于新生代所有對象總空間,如果條件成立的話,那么 Minor GC 可以確認是安全的。

如果不成立的話虛擬機會查看 HandlePromotionFailure 的值是否允許擔保失敗,如果允許那么就會繼續檢查老年代最大可用的連續空間是否大于歷次晉升到老年代對象的平均大小,如果大于,將嘗試著進行一次 Minor GC;如果小于,或者 HandlePromotionFailure 的值不允許冒險,那么就要進行一次 Full GC。

巨人的肩膀

https://github.com/CyC2018/CS-Notes

本文轉載自微信公眾號「多選參數」,可以通過以下二維碼關注。轉載本文請聯系多選參數公眾號。

 

責任編輯:武曉燕 來源: 多選參數
相關推薦

2021-04-29 11:18:14

JVM加載機制

2010-12-10 15:40:58

JVM內存管理

2010-09-26 16:42:04

JVM內存組成JVM垃圾回收

2010-09-26 13:23:13

JVM內存管理機制

2010-09-27 13:26:31

JVM內存管理機制

2020-07-09 12:50:29

JVM內存管理Java

2019-12-10 08:59:55

JVM內存算法

2020-11-06 07:11:40

內存虛擬Redis

2017-05-05 09:13:07

深度學習AI決策樹

2009-07-09 09:47:26

Sun JVM

2017-05-04 13:11:28

深度學習AI

2012-05-15 02:04:22

JVMJava

2015-07-16 15:16:41

內存泄露解決辦法

2010-08-04 13:30:07

Visual Stud

2017-09-20 08:48:09

JVM內存結構

2011-12-20 10:43:21

Java

2010-09-25 15:40:52

配置JVM內存

2012-01-11 10:45:57

JavaJVM

2023-11-19 23:29:22

Heap DumpJava

2018-04-08 08:45:53

對象內存策略
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久精品亚洲 | 久久精品网 | 欧洲精品一区 | 国产 欧美 日韩 一区 | 在线看av网址 | 亚州精品天堂中文字幕 | 人人鲁人人莫人人爱精品 | 先锋资源网站 | 中文字幕一区在线观看视频 | 国产日韩欧美二区 | 羞羞视频网站免费看 | 国产成人精品免高潮在线观看 | 国产精品精品 | 亚洲精品一区二三区不卡 | 欧洲精品在线观看 | 亚洲欧美一区二区三区在线 | 亚洲精品一区在线观看 | 欧美日韩综合视频 | 色噜噜狠狠色综合中国 | 免费日韩网站 | 99在线免费观看视频 | 美女张开腿露出尿口 | 91精品国产综合久久婷婷香蕉 | 免费黄色av| 成人不卡视频 | 亚洲福利在线观看 | 欧美精品在欧美一区二区少妇 | 欧美亚洲日本 | 综合激情网 | 成人不卡| 日韩字幕一区 | 欧美韩一区二区三区 | 一区二区三区日韩 | 一级片片 | av在线免费不卡 | 国产乱码精品一区二区三区忘忧草 | 91精品国产综合久久久久久丝袜 | 日韩在线观看中文字幕 | 国产免费色 | 成人午夜在线 | 日韩免费高清视频 |