日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

笔记:深入理解JVM 第3章 垃圾回收器与内存分配策略

發(fā)布時(shí)間:2024/4/17 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 笔记:深入理解JVM 第3章 垃圾回收器与内存分配策略 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、對(duì)象是否已死

(1). 引用計(jì)數(shù)法:無法回收相互引用的對(duì)象,故JVM沒有采用

例子:?

public class ReferenceObj { public ReferenceObj refObj; } public static void main(String[] args){ReferenceObj obj1 = new ReferenceObj(); ReferenceObj obj2 = new ReferenceObj(); obj1.refObj = obj2; obj2.refObj = obj1; obj1 = null; obj2 = null; }

以上例子使用引用計(jì)數(shù)法無法回收,但是JVM使用的不是,JVM可回收。

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

通過一系列“GC root” 作為起始點(diǎn),從這些節(jié)點(diǎn)開始往下搜索,搜索經(jīng)過的路徑成為引用鏈。若對(duì)象不與引用鏈相連接,則該對(duì)象不可用,可被回收。

GC root的對(duì)象有:

a. 虛擬機(jī)棧中引用的對(duì)象

b. 方法區(qū)中類靜態(tài)屬性引用的對(duì)象

c. 方法區(qū)中常量引用的對(duì)象

d. 本地方法棧中JNI引用的對(duì)象

(3).引用的類型

強(qiáng)引用:引用存在則不會(huì)回收

軟引用:內(nèi)存不足,則回收

弱引用:不管內(nèi)存是否足夠,必定回收

虛引用:無法通過虛引用獲得對(duì)象,只為在回收之前獲得系統(tǒng)通知

(4).finalize 方法可使得對(duì)象在回收之前復(fù)活,但是不建議使用

(5). 方法區(qū)(持久代)回收

方法區(qū)中無用的常量、無用的類會(huì)被回收。判斷無用的類的準(zhǔn)則,,同時(shí)滿足:

a.該類的所有實(shí)例已經(jīng)回收

b.該類的ClassLoader已經(jīng)回收

c.該類的Class 對(duì)象不再被引用。

JVM 通過設(shè)置 -Xnoclaagc 控制。

在大量使用反射、動(dòng)態(tài)代理、CGLib等框架,動(dòng)態(tài)生成JSP、OSGI等頻繁定義ClassLoader場景下都需要JVM具備卸載類的功能,保證方法區(qū)不溢出。


2、垃圾回收算法

(1).標(biāo)記-清除算法

最簡單的算法。

不足:效率低;內(nèi)存產(chǎn)生大量碎片。

(2). 復(fù)制算法 (?新生代)

兩塊內(nèi)存,每次使用一塊,回收時(shí)候?qū)?duì)象從塊A移到塊B,再清理塊A。

優(yōu)點(diǎn):簡單、高效,無碎片。

缺點(diǎn):內(nèi)存使用率低。

新生代一般用的是復(fù)制算法。因?yàn)樾律袑?duì)象98%是“朝生夕死”,所以兩塊內(nèi)存不需要1:1,而是使用1塊比較大的Eden和2塊比較小的Survivor。回收時(shí),將Eden和Survivor A中還存活的數(shù)據(jù)移動(dòng)到Survivor B,再清理Eden 和 ?Survivor A;再次回收時(shí)候,將Eden和Survivor B中還存活的數(shù)據(jù)移動(dòng)到Survivor A,再清理Eden 和 ?Survivor B。JVM 默認(rèn)Eden 和 Survivor的比例是8:1, 即Eden: Survivor A: Survivor B ?= ?8 :0.5:0.5 。當(dāng)回收時(shí)候 Survivor 不夠用時(shí)候, 對(duì)象將被移動(dòng)到老生代。

(3). 標(biāo)記-整理算法 (老生代)

先標(biāo)記,再讓所有存活的對(duì)象向一端移動(dòng),然后直接清除端邊界一外的內(nèi)存。

(4). 分代收集算法

也就是新生代用 “復(fù)制" 算法,老生代用 “標(biāo)記-整理” 或者 "標(biāo)記-清除" 算法。

?


3、HotSpot 的JVM 算法的實(shí)現(xiàn)

GC 導(dǎo)致必須停頓所有Java執(zhí)行進(jìn)程的原因:枚舉根節(jié)點(diǎn),作可達(dá)性分析。

4、垃圾收集器

(1). ?Serial ?收集器??(新生代)

基于復(fù)制算法。

只使用單線程,在垃圾收集時(shí)候,必須暫停其他所有線程,直到其收集結(jié)束 (stop the world)。Serial Collector 是Client模式下,新生代的默認(rèn)收集器。

(2). ParNew 收集器 (Parallel New 收集器) (新生代)?

基于復(fù)制算法。

是Serial Collector 的多線程版本,也必須暫停其他所有線程。?ParNew Collector 是Server模式下,新生代的默認(rèn)收集器。使用 -XX: UseParNewGC 打開。

當(dāng)老生代使用 -XX:+UseConcMarkSweepGC 時(shí)候,新生代必須使用?Serial Collector 或 ?ParNew Collector ,默認(rèn)是?ParNew Collector ?。

默認(rèn)開啟的線城數(shù)目與CPU核數(shù)目一致。

(3). Parallel Scavenge 收集器 ?(新生代)

基于復(fù)制算法。

與ParNew Collector 相比,可以控制最大垃圾收集停頓時(shí)間-XX:MaxGCPauseMillis 和 吞吐量-XX: GCTimeRadio,-XX:

最大垃圾收集停頓時(shí)間-XX:MaxGCPauseMillis=500:停頓時(shí)間越短,則垃圾回收越頻繁。

吞吐量-XX:GCTimeRadio=99:吞吐量 = (用戶線程使用CPU時(shí)間) / (用戶線程使用CPU時(shí)間 + GC線程使用CPU時(shí)間)

自適應(yīng)調(diào)節(jié)策略 -XX:+UseAdaptiveSizePolicy: 開啟后系統(tǒng)會(huì)使用當(dāng)前系統(tǒng)的運(yùn)行情況收集性能監(jiān)控信息,動(dòng)態(tài)調(diào)整停頓時(shí)間和吞吐量。

(4). Serial Old 收集器 ?(老生代)

基于標(biāo)記-整理算法。

Serial 收集器的老生代版本。三個(gè)方面用途:

a. Client 模式下用

b. Server 模式下老版本的JVM 與Parallel Scavenge 搭配使用

c. ?作為老生代CMS的后備方案,失敗的時(shí)候使用。

(5). Parallel Old 收集器

基于“標(biāo)記-整理”算法。

Parallel Scavenge 的老生代版本。一般用于 與新生代的?Parallel Scavenge 相搭配,整個(gè)系統(tǒng)吞吐量優(yōu)先。

(6). CMS 收集器

基于“標(biāo)記-清除”

Concurrent Mark Sweep ,以獲取最短時(shí)間停頓為目標(biāo)的收集器。互聯(lián)網(wǎng)站和B/S系統(tǒng)的服務(wù)端,一般都用CMS,以保證服務(wù)的響應(yīng)速度,停頓時(shí)間短,給用戶帶來較好地體驗(yàn)。

包括4個(gè)步驟:初始標(biāo)記、并發(fā)標(biāo)記、初始標(biāo)記、并發(fā)清除。

優(yōu)點(diǎn):并發(fā)收集、低停頓。

缺點(diǎn):

a. 對(duì)CPU資源敏感,即占用大量CPU資源,不會(huì)導(dǎo)致用戶線程停頓但是會(huì)變慢;

b. 無法處理浮動(dòng)垃圾,即在清理階段產(chǎn)生的垃圾,這些垃圾必須在下一次GC時(shí)候回收,所以還必須預(yù)留部分空間,設(shè)置-XX:CMSInitiatingOccupancyFraction 來提前觸發(fā) (默認(rèn) 92% 觸發(fā))

c. ?收集結(jié)束會(huì)產(chǎn)生空間碎片,設(shè)置+UseCMSCompactAtFullCollection 整理空間碎片。

(7) G1 收集器 ?(新生代、老生代)

Garbage First ,未來可能替換CMS。特點(diǎn):

a. 并發(fā)與并行

b. 分代收集

c.空間整合,使用“標(biāo)記-整理”算法,不會(huì)產(chǎn)生空間碎片

d.可預(yù)測的停頓

現(xiàn)在還沒有廣泛運(yùn)用。

5、配置參數(shù)總結(jié)

-XX:+UseSerialGC ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??使用?Serial +?Serial Old 收集器

-XX:+UseParNewGC? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 使用ParNew + Serial Old 收集器

-XX:+UseConcMarkSweepGC? ? ? ? ? ? ? ? ? ? ? 使用ParNew + CMS + Serial Old (失敗后的預(yù)備方法)

-XX:+UseParallGC? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 使用 Parallel Scavenge + ?Serial Old?

-XX:+UseParallelOldGC ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??使用?Parallel Scavenge + ?Parallel Old

-XX:SurvivorRatio=8 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?新生代中Eden 與 Survivor 的比例,默認(rèn)8

-XX:PretenureSizeThreshold=1024 ? ? ? ? ? ?大于此參數(shù)的對(duì)象直接分配在老生代

-XX:MaxTenuringThreshold=5 ? ? ? ? ? ? ? ? ??新生代中對(duì)象年齡超過此值,移動(dòng)到老生代

-XX:+UseAdaptiveSizePolicy ?? ? ? ? ? ? ? ? ? ? ? 動(dòng)態(tài)調(diào)整Java 堆中各區(qū)域大小 以及進(jìn)入老生代的年齡

-XX:+HandlePromotionFailure ? ? ? ? ? ? ? ? ? ??是否允許分配擔(dān)保失敗

-XX:ParallelGCThreads=10 ? ? ? ? ? ? ? ? ? ? ? ??GC并行線程個(gè)數(shù)

-XX:GCTimeRatio=98 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?GC吞吐量,僅在Parallel Scavenge 有效

-XX:MaxGCPauseMillis=500? ? ? ? ? ? ? ? ? ? ? ? GC最大停頓時(shí)間,僅在Parallel Scavenge 有效

-XX:CMSInitiatingOccupancyFraction=70 ? ?CMS在使用70%觸發(fā), 默認(rèn)68%

-XX:+UseCMSCompactAtFullCollection ?? ? ? ?CMS后進(jìn)行內(nèi)存整理

-XX:CMSFullGcsBeforeCompaction=5 ? ? ? ??CMS 5次后進(jìn)行碎片整理


6. ?理解GC日志

[GC ? ? ? ? ?:GC 沒有發(fā)生Stop-The-World停頓

[Full GC ? :GC 發(fā)生了Stop-The_World

[Full GC(System) : ?GC 由System.gc() 調(diào)用

[DefNew ? : 新生代使用了默認(rèn)的Serial 收集器 Default New Generation

[Tenured: ? 老生代 ?Tenured?Generation

[Perm: ? 持久帶 ?Perm Generation

[ParNew: ?新生代使用ParNew收集器 Parallel New Generation

[PSYoungGen: ?新生代使用Parallel Scavenge 收集器?

3324K ->152K (3712K) : ?GC前為3324K -> GC后為152k (總?cè)萘繛?712K)

[Times: user=0.01, sys=0.00 , real=0.02secs] ?: 用戶態(tài)消耗的CPU時(shí)間、內(nèi)核態(tài)消耗的CPU時(shí)間、墻鐘時(shí)間。墻鐘時(shí)間包括CPU時(shí)間與非運(yùn)算的等待消耗,如等待磁盤IO、等待線程阻塞。



7、內(nèi)存分配與回收策略

(1)、對(duì)象優(yōu)先在Eden分配

大多數(shù)情況下,對(duì)象在新生代的Eden區(qū)分配,當(dāng)Eden區(qū)沒有足夠的空間進(jìn)行分配適合,虛擬機(jī)會(huì)進(jìn)行一次 Minor GC。

配置:?

-Xmx20M -Xms20M -Xmn10M -verbose:gc -XX:+PrintGCDetails -XX:SurvivorRatio=8

代碼:

public class MinorGCTest {private static final int _1MB = 1024 * 1024;public static void main(String[] args) {byte[] allocate1, allocate2, allocate3, allocate4;allocate1 = new byte[2*_1MB];allocate2 = new byte[3*_1MB];allocate3 = new byte[3*_1MB];allocate4 = new byte[4*_1MB];} }

輸出:?

[GC [PSYoungGen: 5792K->600K(9216K)] 5792K->5720K(19456K), 0.0022215 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]?
[Full GC [PSYoungGen: 600K->0K(9216K)] [ParOldGen: 5120K->5589K(10240K)] 5720K->5589K(19456K) [PSPermGen: 2508K->2507K(21504K)], 0.0091615 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]?
Heap
?PSYoungGen ? ? ?total 9216K, used 6727K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
? eden space 8192K, 82% used [0x00000000ff600000,0x00000000ffc91c28,0x00000000ffe00000)
? from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
? to ? space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
?ParOldGen ? ? ? total 10240K, used 5589K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
? object space 10240K, 54% used [0x00000000fec00000,0x00000000ff1754e0,0x00000000ff600000)
?PSPermGen ? ? ? total 21504K, used 2517K [0x00000000f9a00000, 0x00000000faf00000, 0x00000000fec00000)
? object space 21504K, 11% used [0x00000000f9a00000,0x00000000f9c75520,0x00000000faf00000)


(2)、大對(duì)象直接進(jìn)入老生代

可通過 -XX:PretenureSizeThreshold 設(shè)置。寫程序應(yīng)該避免大對(duì)象。

配置:

-Xmx20M -Xms20M -Xmn10M -verbose:gc -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728代碼:

public class PretenureSizeThresholdTest {private static final int _1MB = 1024 * 1024;public static void main(String[] args) {byte[] allocate1;allocate1 = new byte[8*_1MB];} }
輸出:?

Heap
?PSYoungGen ? ? ?total 9216K, used 835K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
? eden space 8192K, 10% used [0x00000000ff600000,0x00000000ff6d0fc0,0x00000000ffe00000)
? from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
? to ? space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
?ParOldGen ? ? ? total 10240K, used 8192K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
? object space 10240K, 80% used [0x00000000fec00000,0x00000000ff400010,0x00000000ff600000)
?PSPermGen ? ? ? total 21504K, used 2515K [0x00000000f9a00000, 0x00000000faf00000, 0x00000000fec00000)
? object space 21504K, 11% used [0x00000000f9a00000,0x00000000f9c74cd0,0x00000000faf00000)


(3)、長期存活的對(duì)象移動(dòng)到老生代

通過-XX:MaxTenuringThreshold 設(shè)定。?

配置

-Xmx20M -Xms20M -Xmn10M -verbose:gc -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC 代碼:

private static final int _1MB = 1024 * 1024;public static void main(String[] args) {byte[] allocate1, allocate2, allocate3, allocate4;allocate1 = new byte[ _1MB/4];allocate2 = new byte[4*_1MB];allocate3 = null;allocate3 = new byte[4*_1MB]; }
輸出:

[GC[ParNew: 5024K->758K(9216K), 0.0021874 secs] 5024K->4856K(19456K), 0.0022406 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]?
Heap
?par new generation ? total 9216K, used 5346K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
? eden space 8192K, ?56% used [0x00000000f9a00000, 0x00000000f9e7af60, 0x00000000fa200000)
? from space 1024K, ?74% used [0x00000000fa300000, 0x00000000fa3bdaa0, 0x00000000fa400000)
? to ? space 1024K, ? 0% used [0x00000000fa200000, 0x00000000fa200000, 0x00000000fa300000)
?concurrent mark-sweep generation total 10240K, used 4098K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
?concurrent-mark-sweep perm gen total 21248K, used 2519K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)

?


(4)、動(dòng)態(tài)對(duì)象年齡判定

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



(5)、空間分配擔(dān)保

在發(fā)生Minor GC 之前, 虛擬機(jī)會(huì)先檢查老生代最大可用的連續(xù)空間是否大于新生代所有對(duì)象總空間,如果成立,則Minor GC可用確保是安全的。在JDK 1.6_24 之后,只要大于,則進(jìn)行Minor GC, 否則則進(jìn)行Full GC。?


8. 新生代GC 和 老生代GC 各自特點(diǎn)

新生代GC:Minor GC,因?yàn)樾律膶?duì)象大多數(shù)朝生夕滅,所以非常頻繁,回收速度也很快。

老生代GC:Major GC/Full GC, ?其速度比 Minor GC 慢10倍以上。



轉(zhuǎn)載于:https://www.cnblogs.com/leeeee/p/7276309.html

總結(jié)

以上是生活随笔為你收集整理的笔记:深入理解JVM 第3章 垃圾回收器与内存分配策略的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。