您好,登錄后才能下訂單哦!
本篇內容主要講解“java內存分布的實現方法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“java內存分布的實現方法”吧!
一、堆內內存
1.1 年輕代-Young Generation
1.2 老年代 (Old Generation)
1.3 元數據(Meta space)
1.4 小結
二、堆外內存
2.1 java中在堆外開辟內存的方法有兩種
2.2 使用堆外內存的優點
2.3堆外內存的缺點
三、垃圾回收
3.1 垃圾回收(GC)
3.2 GC root
3.3常用垃圾回收器
堆內內存分為三大部分,年輕代 , 老年代 和 元空間,所以 堆內內存 = 年輕代 + 老年代 + 元空間,下面細聊下三部分
存放的是new 生成的對象
年輕代是為了盡可能快速的回收掉那些生命周期短的對象
Eden
大部分對象在Eden區中生成
當Eden區滿時,會做一次young gc, 依然存活的對象將被復制到Survivor區, 當一個Survivor 區滿時, 此區的存活對象將被復制到另外一個Survivor區
Survivor(通常2個)
當兩個 Survivor 區 都滿時, 從第一個Survivor 區 被復制過來 且 依舊存活的 對象,超過一定年齡的會被復制到 老年代(Tenured)
Survivor 的兩個區是對稱的, 沒有先后關系, 所有同一個區中可能同時存在從Eden復制過來的對象 和 從前一個 Survivor 復制過來的對象。
把age大于-XX:MaxTenuringThreshold的對象晉升到老年代;(對象每在Survivor區熬過一次,其age就增加一歲);
存放了在年輕代中經歷了N次垃圾回收后仍存活的對象, 是一些生命周期較長的對象.
存放那些創建的時候占用空間比較大的對象,這些對象不經歷eden,直接進入老年代,大對象(大小大于-XX:PretenureSizeThreshold的對象)
存放類的數據
存放靜態文件, 如靜態類和方法等。持久代對垃圾回收沒有顯著影響, 但是有些應用可能動態生成或者調用一些class, 比如Hibernate, Mybatis 等, 此時需要設置一個較大的持久代空間來存放這些運行過程中新增的類。
設置持久代大小參數: -XX:MetaspaceSize, -XX:MaxMetaspaceSize
1、默認參數:
老年代占整個堆內存的2/3
年輕代占整個內存的1/3
Eden 區域占 整個年輕代的80%,From 和 To 兩個生存者區域各占10%
2、新老年代相關jvm參數
-XX:NewRatio
設置新老年代比例,如-XX:NewRatio=5 代表 新老年代比例為1:5,新生代占用堆內存的1/6,老年代占用5/6;
-XX:SurvivorRatio
設置新生代中eden和兩個2個Survivo區域大小的比例,如-XX:SurvivorRatio=8
,則eden:s1:s2=8:1:1,默認比例就是為8:1:1.
3、young GC發生在新生代中,FUll GC 發生在整個堆空間中,一般是老年代空間不夠用就會出發FULL GC
我們的游戲服務器使用的是netty,所以單說下netty,Netty的ByteBuffer采用DIRECT BUFFERS,使用堆外直接內存進行Socket讀寫,不需要進行字節緩沖區的二次拷貝,堆外內存的零拷貝.提升了效率。因為操作系統內核直接把數據寫到堆外內存里,不需要像普通API一樣,操作系統內核緩存一份,程序讀的時候再復制一份到程序空間。
1.用DirectBufferByteBuffer.allocateDirect(size)
2.用JNI寫java的c/c++擴展,在擴展里不牽扯jvm自己向系統搞內存出來。
1.減少了垃圾回收因為垃圾回收會暫停其他的工作。
2.加快了復制的速度堆內在flush到遠程時,會先復制到直接內存(非堆內存),然后在發送;而堆外內存相當于省略掉了這個工作。
內存難以控制,使用了堆外內存就間接失去了JVM管理內存的可行性,改由自己來管理,當發生內存溢出時排查起來非常困難。
Minor GC
一般當新對象生成并且在Eden申請空間失敗時就會觸發MinorGC, 對Eden區域進行GC, 清除非存活對象, 并且把尚存活的對象移動到Survivor區, 然后整理兩個Survivor區。
該方式的GC是對年輕代的Eden區進行,不會影響到年老代。
由于大部分對象是從Eden區開始的, 所以Eden區的GC會很頻繁。
Major GC / Full GC
老年代(Tenured) 被寫滿
持久代(Permanent) 被寫滿
System.gc() 被顯示調用
上一次GC之后Heap 的各域分配策略動態變化
對整個堆進行整理。
所消耗的時間較長, 所以要盡量減少 Full GC 的次數
出現Full GC經常會伴隨至少一次的Minor GC(不是絕對,Parallel Sacvenge收集器就可以選擇設置Major GC策略);
Major GC速度一般比Minor GC慢10倍以上。
程序把所有的引用關系看作一張圖,從一個節點GC ROOT開始,尋找對應的引用節點,找到這個節點以后,繼續尋找這個節點的引用節點,當所有的引用節點尋找完畢之后,剩余的節點則被認為是沒有被引用到的節點,即無用的節點,是需要釋放內存的對象。
java中可作為GC Root的對象有
1.虛擬機棧中引用的對象(本地變量表)
2.方法區中靜態屬性引用的對象
3方法區中常量引用的對象
4.本地方法棧中引用的對象(Native對象)
垃圾收集器就是內存回收的具體實現。下面介紹一下虛擬機提供的幾種垃圾收集器
Serial收集器(復制算法)
新生代單線程收集器,標記和清理都是單線程,優點是簡單高效。
Serial Old收集器(標記-整理算法)
老年代單線程收集器,Serial收集器的老年代版本。
ParNew收集器(停止-復制算法)
新生代收集器,可以認為是Serial收集器的多線程版本,在多核CPU環境下有著比Serial更好的表現。
Parallel Scavenge收集器(停止-復制算法)
并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般為99%, 吞吐量= 用戶線程時間/(用戶線程時間+GC線程時間)。適合后臺應用等對交互相應要求不高的場景。
Parallel Old收集器(停止-復制算法)
Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量優先
CMS(Concurrent Mark Sweep)收集器(標記-清理算法)
高并發、低停頓,追求最短GC回收停頓時間,cpu占用比較高,響應時間快,停頓時間短,多核cpu 追求高響應時間的選擇
G1(Garbage-First)
現在最新的回收器,新生代和老年代通用
新生代收集器使用的收集器:Serial
、PraNew
、Parallel Scavenge
老年代收集器使用的收集器:Serial Old
、Parallel Old
、CMS
我們線上服務器使用的是G1 收集器
上面列舉了很多的內容,但是需要記住的下面幾點就可以了
1、對象的遷移路徑:出生在Eden,然后在Survivor 區域來回遷移,遷移一次一次增加一次年齡,年齡太大的直接進入老年代
2、 Eden區域滿了 產生 minor Gc
老年代滿了產生 full gc
3、記住回收器是執行gc 的,選擇最新的G1回收器就好了
到此,相信大家對“java內存分布的實現方法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。