您好,登錄后才能下訂單哦!
Java中怎么實(shí)現(xiàn)內(nèi)存回收,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
各個(gè)線程共享的內(nèi)存區(qū)域,用于儲(chǔ)蓄已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。 方法區(qū)有時(shí)也被稱為永久代。在 JDK1.8 及之后取消了永久代,取而代之的是元空間。在永久代中做調(diào)優(yōu)是十分困難的,且效果不明顯。永久代的空間大小受制于 JVM 本身內(nèi)存限制,而元空間是直接使用機(jī)器的內(nèi)存,只受系統(tǒng)內(nèi)存限制。元空間默認(rèn)最大大小為無限制。 一些參數(shù):
-XX:PermSize=N //方法區(qū)初始大小 -XX:MaxPermSize=N //方法區(qū)的最大大小 -XX:MetaspaceSize=N //元空間的初始大小 -XX:MaxMetaspaceSize=N //原空間的最大大小
堆是 Java 虛擬機(jī)所管理的內(nèi)存中最大的一塊,是所有線程所共享的,此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例。堆是垃圾收集器管理的主要區(qū)域。在 HotSpot 中,大多數(shù)情況下內(nèi)存被分為新生代和老年代,默認(rèn)分配比例為 1:2。在新生代中又被分為一個(gè) Eden 和兩個(gè) Survivor ,分配比例為 8:1:1。新生代中對(duì)象的年齡在經(jīng)歷一次 Minor GC 后年齡會(huì)+1,當(dāng)年齡達(dá)到15(默認(rèn)值)后會(huì)進(jìn)入老年代。 一些參數(shù):
-XX:InitialHeapSize=N //堆初始大小 -Xms1024m //簡(jiǎn)寫值 -XX:MaxHeapSize=N //堆的最大值 -Xmx1024m //簡(jiǎn)寫值 -XX:MaxTenuringThreshold=15 //新生代進(jìn)入老年代的年齡
線程私有,用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。包含程序計(jì)數(shù)器、虛擬機(jī)棧和本地方法棧。
哪些對(duì)象需要回收?
引用計(jì)數(shù)算法 給對(duì)象一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器就加 1,當(dāng)引用失效時(shí)就減 1。任何計(jì)數(shù)器為 0 的對(duì)象都是不被使用的對(duì)象。 缺點(diǎn):難以解決循環(huán)引用問題。
可達(dá)性分析算法 通過一系列的“GC Roots”作為起點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所達(dá)到的路徑稱為引用鏈。當(dāng)一個(gè)對(duì)象不在任何引用鏈中,則此對(duì)象是不被使用的對(duì)象。
什么時(shí)候回收? 在 可達(dá)性分析算法 中從 GC Roots 搜索時(shí),必須保證引用的一致性,以使對(duì)象的引用關(guān)系不再發(fā)生變化。這點(diǎn)就導(dǎo)致了 GC 必須停止所有的執(zhí)行線程(Stop The World)。 在 HotSpot 中使用 OopMap 來記錄調(diào)用信息。在代碼中有 OopMap 記錄的地方稱為 SafePoint。當(dāng) GC 發(fā)生時(shí),需要讓所有線程先跑到 SafePoint 再執(zhí)行 GC 操作。
如何回收?
標(biāo)記-清除算法 同名字一樣,這個(gè)方式分為“標(biāo)記”和“清除”兩個(gè)階段,首先對(duì)不被使用的對(duì)象添加一個(gè)標(biāo)記,之后對(duì)所有標(biāo)記到的對(duì)象進(jìn)行統(tǒng)一回收。 缺點(diǎn):
標(biāo)記和清除兩個(gè)階段的效率都不高
在回收之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,導(dǎo)致以后難以儲(chǔ)存較大的對(duì)象
復(fù)制算法 將對(duì)象分為兩塊,當(dāng)一塊對(duì)象用完了,就將還在使用的對(duì)象復(fù)制到另一塊對(duì)象上去。較 標(biāo)記-清除算法 有更高的效率 缺點(diǎn):每次只能使用一塊內(nèi)存,使內(nèi)存的利用率變低了。
標(biāo)記-整理算法 前半部分和 標(biāo)記-清除算法 一樣,但后續(xù)將所有存活的對(duì)象移向一端,清除了內(nèi)存碎片。
分代收集算法 根據(jù)對(duì)象的不同存活周期,一般把對(duì)象分為新生代和老年代,根據(jù)各個(gè)年代的特點(diǎn)采用不同的收集算法。 對(duì)于新生代,每次都有大量對(duì)象死去,故采用復(fù)制算法。 對(duì)于老年代,對(duì)象存活率高,采用 標(biāo)記-清除 或 標(biāo)記-整理 算法。
如果說收集算法是內(nèi)存回收的方法論,那么垃圾收集器就是內(nèi)存回收的具體實(shí)現(xiàn)。
Serial 一個(gè)最基本、發(fā)展歷史最悠久的收集器。采用單線程的收集方式,且在收集時(shí)必須暫停其他所有的工作線程,直到收集結(jié)束。在 Client 模式下有較好效果。
ParNew ParNew 收集器就是 Serial 的多線程版本,能與 CMS 配合工作。
Parallel Scavenge 吞吐量?jī)?yōu)先的收集器。(吞吐量=用戶代碼運(yùn)行時(shí)間/(用戶代碼運(yùn)行時(shí)間+垃圾收集時(shí)間))
Serial Old Serial 的老年代版本
Parallel Old Parallel Scavenge 的老年代版本,JDK1.7、JDK1.8 中以 Parallel Scavenge + Parallel Old 為默認(rèn)的新生代、老年代回收器。
CMS 以最短回收停頓時(shí)間為目的,對(duì) CPU 資源敏感
G1 JDK1.9 中的默認(rèn)垃圾收集器,G1 的主要關(guān)注點(diǎn)在于達(dá)到可控的停頓時(shí)間,在這個(gè)基礎(chǔ)上盡可能提高吞吐量。G1 中每個(gè)塊也會(huì)充當(dāng) Eden、Survivor、Old 三種角色,但是它們不是固定的,這使得內(nèi)存使用更加地靈活。
在 HotSpot 中,大多數(shù)情況下內(nèi)存被分為新生代和老年代,默認(rèn)分配比例為 1:2。在新生代中又被分為一個(gè) Eden 和兩個(gè) Survivor ,分配比例為 8:1:1。 一個(gè)新的對(duì)象一般會(huì)在新生代 Eden 區(qū)中分配。當(dāng) Eden 區(qū)沒有足夠空間進(jìn)行分配時(shí),將發(fā)起一次 Minor GC。 對(duì)于大對(duì)象(大量連續(xù)內(nèi)存空間的Java對(duì)象),會(huì)直接進(jìn)入老年代。 長(zhǎng)期存活的對(duì)象(默認(rèn)熬過 15 次 Minor GC),會(huì)進(jìn)入老年代。 如果在 Survivor 中相同年齡的對(duì)象超過了 Survivor 的一般,這些對(duì)象將會(huì)直接進(jìn)入老年代。
一些用于監(jiān)視虛擬機(jī)狀態(tài)和故障處理的命令
命令 | 作用 |
---|---|
jps | 顯示系統(tǒng)內(nèi)所有虛擬機(jī)進(jìn)程 |
jstat | 用于收集虛擬機(jī)各方面運(yùn)行數(shù)據(jù) |
jinfo | 顯示虛擬機(jī)配置信息 |
jmap | 生成虛擬機(jī)內(nèi)存轉(zhuǎn)儲(chǔ)快照(heapdump文件) |
jhat | 用于分析 heapdump 文件 |
jstack | 顯示虛擬機(jī)線程快照 |
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。