java內(nèi)存分布實(shí)現(xiàn)代碼
一、堆內(nèi)內(nèi)存
堆內(nèi)內(nèi)存分為三大部分,年輕代 , 老年代 和 元空間,所以 堆內(nèi)內(nèi)存 = 年輕代 + 老年代 + 元空間,下面細(xì)聊下三部分
1.1 年輕代-Young Generation
- 存放的是new 生成的對(duì)象
- 年輕代是為了盡可能快速的回收掉那些生命周期短的對(duì)象
- Eden
- 大部分對(duì)象在Eden區(qū)中生成
- 當(dāng)Eden區(qū)滿(mǎn)時(shí),會(huì)做一次young gc, 依然存活的對(duì)象將被復(fù)制到Survivor區(qū), 當(dāng)一個(gè)Survivor 區(qū)滿(mǎn)時(shí), 此區(qū)的存活對(duì)象將被復(fù)制到另外一個(gè)Survivor區(qū)
- Survivor(通常2個(gè))
- 當(dāng)兩個(gè) Survivor 區(qū) 都滿(mǎn)時(shí), 從第一個(gè)Survivor 區(qū) 被復(fù)制過(guò)來(lái) 且 依舊存活的 對(duì)象,超過(guò)一定年齡的會(huì)被復(fù)制到 老年代(Tenured)
- Survivor 的兩個(gè)區(qū)是對(duì)稱(chēng)的, 沒(méi)有先后關(guān)系, 所有同一個(gè)區(qū)中可能同時(shí)存在從Eden復(fù)制過(guò)來(lái)的對(duì)象 和 從前一個(gè) Survivor 復(fù)制過(guò)來(lái)的對(duì)象。
- 把a(bǔ)ge大于-XX:MaxTenuringThreshold的對(duì)象晉升到老年代;(對(duì)象每在Survivor區(qū)熬過(guò)一次,其age就增加一歲);
1.2 老年代 (Old Generation)
- 存放了在年輕代中經(jīng)歷了N次垃圾回收后仍存活的對(duì)象, 是一些生命周期較長(zhǎng)的對(duì)象.
- 存放那些創(chuàng)建的時(shí)候占用空間比較大的對(duì)象,這些對(duì)象不經(jīng)歷eden,直接進(jìn)入老年代,大對(duì)象(大小大于-XX:PretenureSizeThreshold的對(duì)象)
1.3 元數(shù)據(jù)(Meta space)
- 存放類(lèi)的數(shù)據(jù)
- 存放靜態(tài)文件, 如靜態(tài)類(lèi)和方法等。持久代對(duì)垃圾回收沒(méi)有顯著影響, 但是有些應(yīng)用可能動(dòng)態(tài)生成或者調(diào)用一些class, 比如Hibernate, Mybatis 等, 此時(shí)需要設(shè)置一個(gè)較大的持久代空間來(lái)存放這些運(yùn)行過(guò)程中新增的類(lèi)。
- 設(shè)置持久代大小參數(shù):
-XX:MetaspaceSize, -XX:MaxMetaspaceSize
1.4 小結(jié)
1、默認(rèn)參數(shù):
老年代占整個(gè)堆內(nèi)存的2/3
年輕代占整個(gè)內(nèi)存的1/3
Eden 區(qū)域占 整個(gè)年輕代的80%,F(xiàn)rom 和 To 兩個(gè)生存者區(qū)域各占10%
2、新老年代相關(guān)jvm參數(shù)
-XX:NewRatio
設(shè)置新老年代比例,如-XX:NewRatio=5 代表 新老年代比例為1:5,新生代占用堆內(nèi)存的1/6,老年代占用5/6;-XX:SurvivorRatio
設(shè)置新生代中eden和兩個(gè)2個(gè)Survivo區(qū)域大小的比例,如-XX:SurvivorRatio=8
,則eden:s1:s2=8:1:1,默認(rèn)比例就是為8:1:1.
3、young GC發(fā)生在新生代中,F(xiàn)Ull GC 發(fā)生在整個(gè)堆空間中,一般是老年代空間不夠用就會(huì)出發(fā)FULL GC
二、堆外內(nèi)存
我們的游戲服務(wù)器使用的是netty,所以單說(shuō)下netty,Netty的ByteBuffer采用DIRECT BUFFERS,使用堆外直接內(nèi)存進(jìn)行Socket讀寫(xiě),不需要進(jìn)行字節(jié)緩沖區(qū)的二次拷貝,堆外內(nèi)存的零拷貝.提升了效率。因?yàn)椴僮飨到y(tǒng)內(nèi)核直接把數(shù)據(jù)寫(xiě)到堆外內(nèi)存里,不需要像普通API一樣,操作系統(tǒng)內(nèi)核緩存一份,程序讀的時(shí)候再?gòu)?fù)制一份到程序空間。
2.1 java中在堆外開(kāi)辟內(nèi)存的方法有兩種
1.用DirectBufferByteBuffer.allocateDirect(size)
2.用JNI寫(xiě)java的c/c++擴(kuò)展,在擴(kuò)展里不牽扯jvm自己向系統(tǒng)搞內(nèi)存出來(lái)。
2.2 使用堆外內(nèi)存的優(yōu)點(diǎn)
1.減少了垃圾回收因?yàn)槔厥諘?huì)暫停其他的工作。
2.加快了復(fù)制的速度堆內(nèi)在flush到遠(yuǎn)程時(shí),會(huì)先復(fù)制到直接內(nèi)存(非堆內(nèi)存),然后在發(fā)送;而堆外內(nèi)存相當(dāng)于省略掉了這個(gè)工作。
2.3堆外內(nèi)存的缺點(diǎn)
內(nèi)存難以控制,使用了堆外內(nèi)存就間接失去了JVM管理內(nèi)存的可行性,改由自己來(lái)管理,當(dāng)發(fā)生內(nèi)存溢出時(shí)排查起來(lái)非常困難。
三、垃圾回收
3.1 垃圾回收(GC)
Minor GC
- 一般當(dāng)新對(duì)象生成并且在Eden申請(qǐng)空間失敗時(shí)就會(huì)觸發(fā)MinorGC, 對(duì)Eden區(qū)域進(jìn)行GC, 清除非存活對(duì)象, 并且把尚存活的對(duì)象移動(dòng)到Survivor區(qū), 然后整理兩個(gè)Survivor區(qū)。
- 該方式的GC是對(duì)年輕代的Eden區(qū)進(jìn)行,不會(huì)影響到年老代。
- 由于大部分對(duì)象是從Eden區(qū)開(kāi)始的, 所以Eden區(qū)的GC會(huì)很頻繁。
Major GC / Full GC
- 老年代(Tenured) 被寫(xiě)滿(mǎn)
- 持久代(Permanent) 被寫(xiě)滿(mǎn)
- System.gc() 被顯示調(diào)用
- 上一次GC之后Heap 的各域分配策略動(dòng)態(tài)變化
- 對(duì)整個(gè)堆進(jìn)行整理。
- 所消耗的時(shí)間較長(zhǎng), 所以要盡量減少 Full GC 的次數(shù)
出現(xiàn)Full GC經(jīng)常會(huì)伴隨至少一次的Minor GC(不是絕對(duì),Parallel Sacvenge收集器就可以選擇設(shè)置Major GC策略);
Major GC速度一般比Minor GC慢10倍以上。
3.2 GC root
程序把所有的引用關(guān)系看作一張圖,從一個(gè)節(jié)點(diǎn)GC ROOT開(kāi)始,尋找對(duì)應(yīng)的引用節(jié)點(diǎn),找到這個(gè)節(jié)點(diǎn)以后,繼續(xù)尋找這個(gè)節(jié)點(diǎn)的引用節(jié)點(diǎn),當(dāng)所有的引用節(jié)點(diǎn)尋找完畢之后,剩余的節(jié)點(diǎn)則被認(rèn)為是沒(méi)有被引用到的節(jié)點(diǎn),即無(wú)用的節(jié)點(diǎn),是需要釋放內(nèi)存的對(duì)象。
java中可作為GC Root的對(duì)象有
1.虛擬機(jī)棧中引用的對(duì)象(本地變量表)
2.方法區(qū)中靜態(tài)屬性引用的對(duì)象
3方法區(qū)中常量引用的對(duì)象
4.本地方法棧中引用的對(duì)象(Native對(duì)象)
3.3常用垃圾回收器
垃圾收集器就是內(nèi)存回收的具體實(shí)現(xiàn)。下面介紹一下虛擬機(jī)提供的幾種垃圾收集器
Serial收集器(復(fù)制算法)
新生代單線程收集器,標(biāo)記和清理都是單線程,優(yōu)點(diǎn)是簡(jiǎn)單高效。
Serial Old收集器(標(biāo)記-整理算法)
老年代單線程收集器,Serial收集器的老年代版本。
ParNew收集器(停止-復(fù)制算法)
新生代收集器,可以認(rèn)為是Serial收集器的多線程版本,在多核CPU環(huán)境下有著比Serial更好的表現(xiàn)。
Parallel Scavenge收集器(停止-復(fù)制算法)
并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般為99%, 吞吐量= 用戶(hù)線程時(shí)間/(用戶(hù)線程時(shí)間+GC線程時(shí)間)。適合后臺(tái)應(yīng)用等對(duì)交互相應(yīng)要求不高的場(chǎng)景。
Parallel Old收集器(停止-復(fù)制算法)
Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量?jī)?yōu)先
CMS(Concurrent Mark Sweep)收集器(標(biāo)記-清理算法)
高并發(fā)、低停頓,追求最短GC回收停頓時(shí)間,cpu占用比較高,響應(yīng)時(shí)間快,停頓時(shí)間短,多核cpu 追求高響應(yīng)時(shí)間的選擇
G1(Garbage-First)
現(xiàn)在最新的回收器,新生代和老年代通用
新生代收集器使用的收集器:Serial
、PraNew
、Parallel Scavenge
老年代收集器使用的收集器:Serial Old
、Parallel Old
、CMS
我們線上服務(wù)器使用的是G1 收集器
四、總結(jié)
上面列舉了很多的內(nèi)容,但是需要記住的下面幾點(diǎn)就可以了
1、對(duì)象的遷移路徑:出生在Eden,然后在Survivor 區(qū)域來(lái)回遷移,遷移一次一次增加一次年齡,年齡太大的直接進(jìn)入老年代
2、 Eden區(qū)域滿(mǎn)了 產(chǎn)生 minor Gc
老年代滿(mǎn)了產(chǎn)生 full gc
3、記住回收器是執(zhí)行g(shù)c 的,選擇最新的G1回收器就好了
本篇文章就到這里了,希望能給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringBoot自定義Starter與自動(dòng)配置實(shí)現(xiàn)方法詳解
在Spring Boot官網(wǎng)為了簡(jiǎn)化我們的開(kāi)發(fā),已經(jīng)提供了非常多場(chǎng)景的Starter來(lái)為我們使用,即便如此,也無(wú)法全面的滿(mǎn)足我們實(shí)際工作中的開(kāi)發(fā)場(chǎng)景,這時(shí)我們就需要自定義實(shí)現(xiàn)定制化的Starter2023-02-02IDEA2020如何打開(kāi)Run Dashboard的方法步驟
這篇文章主要介紹了IDEA2020如何打開(kāi)Run Dashboard的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07java后端實(shí)現(xiàn)信息分頁(yè)查詢(xún)的示例代碼
在一個(gè)頁(yè)面展示大量的用戶(hù)信息不便于觀看,因此就需要采用分頁(yè)展示的方法,本文就來(lái)為大家介紹一下java后端如何實(shí)現(xiàn)信息分頁(yè)查詢(xún),需要的小伙伴可以參考下2023-11-11Spring cloud alibaba之Gateway網(wǎng)關(guān)功能特征詳解
spring cloud gateway是spring cloud推出的第二代網(wǎng)關(guān),是由WebFlux+Netty+Reactor實(shí)現(xiàn)的響應(yīng)式的API網(wǎng)關(guān),它不能在傳統(tǒng)的servlet容器中工作,也不能構(gòu)建成war包,接下來(lái)通過(guò)本文給大家分享Spring cloud alibaba--Gateway網(wǎng)關(guān),需要的朋友可以參考下2021-08-08maven將項(xiàng)目打包上傳到nexus私服的詳細(xì)教程
這篇文章主要介紹了maven將項(xiàng)目打包上傳到nexus私服,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-07-07JAVA WSIMPORT生成WEBSERVICE客戶(hù)端401認(rèn)證過(guò)程圖解
這篇文章主要介紹了JAVA WSIMPORT生成WEBSERVICE客戶(hù)端401認(rèn)證過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Intellij IDEA中一次性折疊所有Java代碼的快捷鍵設(shè)置
這篇文章主要介紹了Intellij IDEA中一次性折疊所有Java代碼的快捷鍵設(shè)置,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05