內(nèi)存劃分
java虛擬機(jī)會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域
程序計(jì)數(shù)器
當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。字節(jié)碼解釋器通過改變這個(gè)計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令
虛擬機(jī)棧
java方法執(zhí)行的內(nèi)存模型岗宣,它的生命周期與線程相同皿曲。方法執(zhí)行時(shí)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表(存放了各種基本數(shù)據(jù)類型boolean设拟、byte缅阳、char、short频敛、int帮哈、float膛檀、long、double娘侍,對(duì)象引用)咖刃、操作棧、動(dòng)態(tài)鏈接憾筏、方法出口等信息嚎杨。
本地方法棧
虛擬機(jī)使用到的nativie方法服務(wù)
Java堆
存放對(duì)象的實(shí)例,幾乎所有對(duì)象都在這里分配內(nèi)存氧腰。棧上分配枫浙、標(biāo)量替換會(huì)導(dǎo)致其他情況
方法區(qū)
用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量古拴、靜態(tài)變量箩帚、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)
運(yùn)行時(shí)常量池,Class文件中除了類的版本黄痪、字段紧帕、方法、接口等之外還有常量池桅打。用于存放編譯期生成的各種字面量和符號(hào)引用
1.8之后叫元空間
運(yùn)行時(shí)常量池
用于存放編譯期生成的各種字面量和符號(hào)引用焕参,String類的intern()
虛擬機(jī)對(duì)象
對(duì)象的創(chuàng)建
1.類加載檢查
虛擬機(jī)遇到一條new指令,會(huì)首先進(jìn)行類加載的檢查:
--檢查這個(gè)指令的參數(shù)是否在常量池中定位到一個(gè)符號(hào)引用
--檢查該類是否被加載油额、解析和初始化,如果沒有就進(jìn)行類加載刻帚。
2.分配內(nèi)存
對(duì)象所需內(nèi)存的大小在類加載完成后便可完全確定潦嘶,于是分配空間等同于把一塊確定大小的內(nèi)存從堆中劃分出來,具體分配方式取決于堆內(nèi)存是否規(guī)整崇众。是否規(guī)整是垃圾收集器是否帶有壓縮整理功能決定的掂僵。
-- 指針碰撞
堆內(nèi)存規(guī)整航厚,移動(dòng)指針
-- 空閑列表
堆內(nèi)存不規(guī)整,虛擬機(jī)維護(hù)記錄可用內(nèi)存的列表锰蓬,從列表中查找對(duì)應(yīng)對(duì)象大小的內(nèi)存區(qū)域分配給對(duì)象幔睬,并更新空閑列表。
為保證內(nèi)存分配時(shí)并發(fā)情況下線程安全問題芹扭,有兩種方案:
-- CAS+失敗重試
虛擬機(jī)采用CAS配上失敗重試的方式保證更新操作的原子性來對(duì)分配內(nèi)存空間的動(dòng)作進(jìn)行同步處理
-- TLAB
把內(nèi)存分配的動(dòng)作按照線程劃分在不同的空間之中進(jìn)行麻顶,即每個(gè)線程在java堆中預(yù)先分配一小塊內(nèi)存
3.初始化
內(nèi)存分配完成后,虛擬機(jī)需要將除對(duì)象頭以外分配到的內(nèi)存空間都初始化為0舱卡,如果使用TLAB,這一工作過程也可以提前至TLAB分配時(shí)進(jìn)行辅肾。這一步操作保證了對(duì)象的實(shí)例字段在java代碼中可以不賦初始值就直接使用,程序能訪問到這些字段的數(shù)據(jù)類型所對(duì)應(yīng)的零值轮锥。
4.設(shè)置對(duì)象頭
初始化零值之后矫钓,虛擬機(jī)要對(duì)對(duì)象進(jìn)行必要的設(shè)置,這些設(shè)置信息存放在對(duì)象的對(duì)象頭Object Header之中舍杜。
對(duì)象頭包括:markword新娜、類型指針、數(shù)組長度
5.執(zhí)行init方法
為對(duì)象屬性復(fù)制既绩,執(zhí)行對(duì)象的構(gòu)造方法
對(duì)象的內(nèi)存布局
對(duì)象訪問(對(duì)象定位)
1.使用句柄
句柄中包含了對(duì)象實(shí)例數(shù)據(jù)和類型數(shù)據(jù)各自的具體地址信息
2.直接指針
分配對(duì)象
Java 中主要使用 Unsafe 調(diào)用了 C 的 allocate 和 free 兩個(gè)方法概龄,分配方法有兩種:
1.指針碰撞: 始終跟蹤上一次分配對(duì)象時(shí)使用的空間末尾地址。當(dāng)要為新對(duì)象分配空間時(shí)熬词,會(huì)在當(dāng)前所處的代的各個(gè)內(nèi)存塊中查找是否有適合大小的空間來分配給新對(duì)象旁钧,若有,則更新指針互拾,初始化對(duì)象
2.空閑列表: 維護(hù)一個(gè)列表歪今,記錄上哪些內(nèi)存可用。
垃圾對(duì)象
1.引用計(jì)數(shù)算法
給對(duì)象中添加一個(gè)引用計(jì)數(shù)器颜矿,每當(dāng)有一個(gè)地方引用它時(shí)寄猩,計(jì)數(shù)器值加1;當(dāng)引用失效時(shí)骑疆,計(jì)數(shù)器值就減1田篇;任何時(shí)刻計(jì)數(shù)器都為0的對(duì)象就是不可能在被使用
缺點(diǎn)就是相互引用
2.根搜索算法
通過“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索箍铭,搜索所走過的路勁成為引用鏈泊柬,當(dāng)一個(gè)對(duì)象到Gc Roots 沒有任何引用鏈相連,則證明此對(duì)象是不可用的诈火。
Gc Roots對(duì)象包括:
- 虛擬機(jī)棧(棧幀中的本地變量表)中的引用的對(duì)象
- 方法區(qū)中的類靜態(tài)屬性引用的對(duì)象
- 方法區(qū)中的常量引用的對(duì)象
- 本地方法棧中JNI的引用的對(duì)象
什么是引用兽赁?
強(qiáng)引用
只要強(qiáng)引用還在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象
軟引用
在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中并進(jìn)行第二次回收
弱引用
只能生存到下一次來及收集發(fā)生之前刀崖,WeakReference類來實(shí)現(xiàn)弱引用
虛引用
兩次標(biāo)記過程才會(huì)真正死亡惊科。
第一次標(biāo)記:
判斷是否存在引用鏈。然后篩選(判斷是否有必要執(zhí)行finalize方法)亮钦,并放置F-Queue的隊(duì)列中
第二次標(biāo)記
GC將對(duì)F-Queue中的對(duì)象進(jìn)行第二次小規(guī)模的標(biāo)記
垃圾收集算法
1.標(biāo)記-清除算法
首先標(biāo)記出所有需要回收的對(duì)象馆截,在標(biāo)記完成后統(tǒng)一回收掉所有被標(biāo)記的對(duì)象
缺點(diǎn): 1.效率問題。2.空間問題
2.復(fù)制算法
將可用內(nèi)存按容量劃分為大小相等的兩塊蜂莉,每次只使用其中的一塊蜡娶。當(dāng)這一塊用完了。就將存貨著的對(duì)象復(fù)制到另外一塊上巡语。然后將已使用過的內(nèi)存空間一次清理掉翎蹈。
3.標(biāo)記-整理算法
讓所有存貨的對(duì)象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存
3.分代收集算法
根據(jù)對(duì)象的存貨周期的不同將內(nèi)存劃分為幾塊男公。一般是把java堆分為新生代和老年代荤堪。這樣可以根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴ā?/p>
垃圾收集器
如果兩個(gè)收集器之間存在連線,說明可以搭配使用枢赔。
Serial收集器
jdk1.3.1之前新生代澄阳,單線程的收集器。收集垃圾時(shí)踏拜,必須暫停其他所有的工作線程
優(yōu)點(diǎn):簡單而高效碎赢,適合client端
ParNew收集器
Serial收集器的多線程版本
Parallel Scavenge收集器
新生代收集器,使用復(fù)制算法并行的多線程收集器速梗。目標(biāo)是達(dá)到一個(gè)可控制的吞吐量
停頓時(shí)間越短就越適合需要與用戶交互的程序肮塞,良好的響應(yīng)速度能提升用戶的體驗(yàn)﹔而高吞吐量則可以最高效率地利用CPU時(shí)間,盡快地完成程序的運(yùn)算任務(wù)姻锁,主要適合在后臺(tái)運(yùn)算而不需要太多交互的任務(wù)枕赵。
Serial Old收集器
老年代版本的單線程收集器。使用“標(biāo)記-整理”算法
Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本位隶,使用多線程和“標(biāo)記-整理”算法拷窜。
CMS收集器
是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器〗Щ疲“標(biāo)記-清除”
優(yōu)點(diǎn):并發(fā)收集篮昧、低停頓
缺陷:對(duì)cpu資源非常敏感、無法處理浮動(dòng)垃圾笋妥、產(chǎn)生大量空間碎片
G1收集器(精準(zhǔn)控制停頓時(shí)間懊昨,避免垃圾碎片)
減少“Stop the world”G1垃圾收集器能同時(shí)回收年輕代和老年代的對(duì)象,它最大的一個(gè)特點(diǎn)是把java堆內(nèi)存拆分為多個(gè)大小相等的region春宣,使得每個(gè)小空間可以單獨(dú)進(jìn)行垃圾回收疚颊。在指定的時(shí)間范圍內(nèi)狈孔,同時(shí)在有限的時(shí)間內(nèi)盡量回收盡可能多的垃圾對(duì)象
維護(hù)了一個(gè)優(yōu)先列表,根據(jù)允許的收集時(shí)間材义,優(yōu)先回收最大的region
G1 收集器兩個(gè)最突出的改進(jìn)是:
【1】基于標(biāo)記-整理算法,不產(chǎn)生內(nèi)存碎片嫁赏。
【2】可以非常精確控制停頓時(shí)間其掂,在不犧牲吞吐量前提下,實(shí)現(xiàn)低停頓垃圾回收潦蝇。(增量回收款熬,不是全量回收)
存放類的信息到元空間
JVM分代模型:年輕代和老年代
對(duì)象的分配機(jī)制
分配機(jī)制
正常情況下是在堆上分配
新生代回收之后,因?yàn)榇婊顚?duì)象太多攘乒,導(dǎo)致大量對(duì)象直接進(jìn)入老年代
特別大的超大對(duì)象直接不經(jīng)過新生代就進(jìn)入老年代
有一個(gè)JVM參數(shù)贤牛,就是“-XX:PretenureSizeThreshold”,可以把他的值設(shè)置為字節(jié)數(shù)则酝。只要對(duì)象大于這個(gè)參數(shù)殉簸,那么會(huì)直接進(jìn)入老年代。避免對(duì)象在survivor 對(duì)象間頻繁復(fù)制長期存活的對(duì)象
虛擬機(jī)給每個(gè)對(duì)象定義了一個(gè)對(duì)象年齡計(jì)數(shù)器沽讹,經(jīng)過一次minorGC后仍然存活般卑,并且被Survivor容納的話,就加一歲爽雄,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲)蝠检,就將晉升到老年代。
年齡閾值可通過“-XX:MaxTenuringThreshold”設(shè)置動(dòng)態(tài)對(duì)象年齡判斷機(jī)制
年齡1+年齡2+年齡n的多個(gè)年齡對(duì)象總和超過了Survivor區(qū)域的50%挚瘟,此時(shí)就會(huì)把年齡n以上的對(duì)象都放入老年代
- 空間擔(dān)保機(jī)制
每一次minor GC 之前叹谁,jvm會(huì)檢查一下老年代可用內(nèi)存空間,是否大于新生代所有對(duì)象的總大小乘盖,假如老年代的內(nèi)存小于新生代的全部對(duì)象大小焰檩,會(huì)看“-XX:-HandlePromotionFailure”的參數(shù)是否設(shè)置了,如果設(shè)置了就判斷老年代的內(nèi)存是否大于之前每一次minor Gc后進(jìn)入老年代的平均對(duì)象大小侧漓。如果小于或者沒有這個(gè)參數(shù)锅尘,那么就會(huì)執(zhí)行full GC。如果執(zhí)行后還是沒有足夠的大小夠放對(duì)象布蔗。那么就會(huì)報(bào)“OOM”
方法區(qū)內(nèi)會(huì)不會(huì)進(jìn)行垃圾回收藤违?
首先該類的所有實(shí)例對(duì)象都已經(jīng)從Java堆內(nèi)存里被回收
其次加載這個(gè)類的ClassLoader已經(jīng)被回收
最后,對(duì)該類的Class對(duì)象沒有任何引用
老年代什么是否觸發(fā)垃圾回收纵揍?
JVM 優(yōu)化之常用參數(shù)
-Xms: 堆最小空間顿乒,建議設(shè)置為物理內(nèi)存的1/4
-Xmx:堆最大空間,建議設(shè)置為物理內(nèi)存的1/2
-XX:NewRatio: Old/New的比例
-Xmn: 年輕代大小泽谨,調(diào)整會(huì)影響老年代大小璧榄,官方建議堆大小的3/8
-XX:SurvivorRatio: 調(diào)整Survivor和Eden的比例大小
-XX:MetaspaceSize: 元空間初始化大小特漩,
-XX:MaxMetaspaceSize: 元空間最大大小
-XX:PretenureSizeThreshold: 大對(duì)象直接進(jìn)入老年代的閾值
-XX:MaxTenuringThreshold: 進(jìn)入老年代的分代年齡閾值
JVM性能調(diào)優(yōu)
常用命令:jps、jinfo骨杂、jstat涂身、jstack、jmap
調(diào)測工具
Arthas