1.深入java虛擬機(jī)

3.JVM

1.虛擬機(jī)?

可以執(zhí)行java字節(jié)碼的虛擬機(jī)進(jìn)程,

.java文件經(jīng)過編譯成能被java虛擬機(jī)執(zhí)行的.class文件

能跨平臺(tái)?

java編譯成響應(yīng)的字節(jié)碼,再不同系統(tǒng)的jvm被執(zhí)行,所有跨平臺(tái)的是java程序,而不是JVM

2.jvm組成

作用

1.程序在執(zhí)行之前要把代碼編譯成字節(jié)碼.class文件 2.jvm通過類加載器將字節(jié)碼文件加載到內(nèi)存中, 3.而字節(jié)碼文件時(shí)jvm的指令集,并不能直接交給底層操作系統(tǒng)去執(zhí)行, 4.而交給解析器執(zhí)行調(diào)用本地接口方法實(shí)現(xiàn)執(zhí)行底層系統(tǒng)指令

a 類加載器

在jvm啟動(dòng)或者類運(yùn)行時(shí),將需要class文件加載到JVM中

b 內(nèi)存區(qū)

見3

c 執(zhí)行引擎

執(zhí)行引擎的任務(wù)負(fù)責(zé)執(zhí)行class文件中包含的字節(jié)碼指令,

d 本地方法調(diào)用

3.jvm內(nèi)存區(qū)-運(yùn)行數(shù)據(jù)區(qū)

jvm-內(nèi)存.jpg

1)方法區(qū)(元空間):

jdk8已經(jīng)被取消,改成了元數(shù)據(jù),

各個(gè)線程共享的一個(gè)區(qū)域,用于存儲(chǔ)虛擬機(jī)加載的類信息,常量,靜態(tài)變量,即時(shí)編譯器編譯后的代碼等數(shù)據(jù)

jdk1.8后,字符串和常量放到堆內(nèi)存中,新增了MetaSpace

大小沒有限制,根據(jù)內(nèi)存大小,動(dòng)態(tài)改變;也可以通過-XX:MetaspaceSize-初始化大小;-XX:MaxMetaspace-最大值,

2)堆內(nèi)存

各個(gè)線程共享的一個(gè)區(qū)域,垃圾收集器管理的主要區(qū)域。

3)本地方法棧

為jvm提供native方法的服務(wù)

jdk里native修飾的方法(本地),會(huì)調(diào)用本地c語(yǔ)言函數(shù)

4)虛擬機(jī)棧

jvm-棧.jpg

線程私有,

每個(gè)方法在執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量,操作數(shù),方法出口等信息

每個(gè)方法調(diào)用,都意味著虛擬機(jī)棧中入棧和出棧的過程

程序計(jì)算器

線程私有,

如果執(zhí)行的時(shí)候java方法,記錄當(dāng)前線程正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址,如果本地方法則為undefined

該內(nèi)存區(qū)域是唯一一個(gè)在java虛擬機(jī)沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。

棧幀:用于支持虛擬機(jī)經(jīng)行方法調(diào)用和方法執(zhí)行的數(shù)據(jù)結(jié)構(gòu),它是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的虛擬機(jī)棧的棧元素。 每一個(gè)方法對(duì)應(yīng)一塊棧幀內(nèi)存區(qū)域, 棧幀里由

局部變量

操作數(shù)棧

動(dòng)態(tài)鏈接,將符號(hào)引用轉(zhuǎn)為直接引用

方法出口

a 淺拷貝和深拷貝

淺拷貝:新增一個(gè)指針,指向原有內(nèi)存地址

深拷貝:新增一個(gè)指針,指向原有內(nèi)存地址的復(fù)制的內(nèi)存地址

b 堆棧區(qū)別

物理地址,堆分配的地址對(duì)象時(shí)不連續(xù)的,因此性能慢,而棧分配的是連續(xù)的,性能高

因?yàn)槎咽遣贿B續(xù)所有內(nèi)存大小是不固定,只有在運(yùn)行期確定,而棧是連續(xù)的,在編譯期就確定了;堆存放的是內(nèi)存對(duì)象,而棧存的是局部變量,操作數(shù)棧,方法出入口,

堆內(nèi)存對(duì)于線程是共享的,棧是線程私有

3.nio直接內(nèi)存?

直接內(nèi)存(Direct Memory),并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是 Java 虛擬機(jī)規(guī)范中農(nóng)定義的內(nèi)存區(qū)域。在 JDK1.4 中新加入了 NIO(New Input/Output) 類,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的 I/O 方式,它可以使用 native 函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通脫一個(gè)存儲(chǔ)在 Java 堆中的 DirectByteBuffer 對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場(chǎng)景中顯著提高性能,因?yàn)楸苊饬嗽?Java 堆和 Native 堆中來(lái)回復(fù)制數(shù)據(jù)

4.創(chuàng)建對(duì)象的方式

方式 注釋
new關(guān)鍵字 調(diào)用構(gòu)造函數(shù)
Class的newInstance 調(diào)用構(gòu)造函數(shù)
Constructor的newInstance 調(diào)用構(gòu)造函數(shù)
clone 未調(diào)用構(gòu)造函數(shù)
反射 未調(diào)用構(gòu)造函數(shù)

1)對(duì)象創(chuàng)建流程

new 類名

-> 虛擬機(jī)遇到一條new指令,檢查常量池中是否已經(jīng)加載了相應(yīng)的類,

->虛擬機(jī)為對(duì)象分配內(nèi)存

->將分配的內(nèi)存初始化為零值(不包括對(duì)象頭)

->調(diào)用對(duì)象init方法

2)為對(duì)象分配內(nèi)存?

指針碰撞

如果java堆的內(nèi)存是規(guī)整的,所有用過的一邊放一邊,而空閑的放另一邊,分配內(nèi)存時(shí),將位于中間的指針指示器將往空閑空間挪動(dòng)一段與對(duì)象大小相等的距離

空閑列表

如果不規(guī)則,虛擬機(jī)必須維護(hù)一個(gè)列表記錄哪些內(nèi)u才能可用,在分配的時(shí)候從列表中找到一塊足夠大的空間劃分給對(duì)象實(shí)例

3)處理并發(fā)問題?

同步處理,采用cas和失敗重試 更新操作的原子性

本地線程分配緩存

4)對(duì)象的訪問定位?

句柄訪問,在堆內(nèi)存中劃分一塊內(nèi)存作為句柄池,引用中存儲(chǔ)對(duì)象的句柄地址,句柄池存儲(chǔ)對(duì)象實(shí)例指針和對(duì)象類型指針,

直接指針

引用中存儲(chǔ)的是對(duì)象地址,對(duì)象地址內(nèi)存存類型數(shù)據(jù)地址,指向方法區(qū)

5.內(nèi)存泄露異常

內(nèi)存泄漏指的是不在使用的對(duì)象或者變量,一直被占用在內(nèi)存中,沒有被回收,

理論上java有垃圾回收機(jī)制,不再使用的對(duì)象,會(huì)被gc自動(dòng)回收,從內(nèi)存中清楚

出現(xiàn)情況:

長(zhǎng)生命周期的對(duì)象持有短生命周期的對(duì)象的引用就很有可能發(fā)生內(nèi)存泄漏

6.垃圾回收機(jī)制

定義

java中,程序員不需要手動(dòng)地去釋放對(duì)象內(nèi)存,而是有虛擬機(jī)自行執(zhí)行,在JVM中有一個(gè)低優(yōu)先級(jí)的垃圾回收線程,在虛擬機(jī)空閑或者內(nèi)存不足的,才會(huì)觸發(fā),掃描那些沒有任何引用的對(duì)象,并將它們添加到回收的集合中,進(jìn)行回收;

1)引用類型

強(qiáng)引用:發(fā)生gc的時(shí)候不會(huì)被回收,需要弱化從而使gc回收

軟引用:在發(fā)生內(nèi)存溢出時(shí)會(huì)被回收

弱引用:在下次gc的時(shí)會(huì)被回收

虛引用:無(wú)法通過虛引用獲取對(duì)象

2)判斷對(duì)象是否可以被回收

引用計(jì)算器法

為每個(gè)對(duì)象創(chuàng)建一個(gè)引用計(jì)數(shù),有對(duì)象引用時(shí)+1,引用釋放計(jì)數(shù)-1,當(dāng)計(jì)數(shù)器為0,就可以被回收,

缺點(diǎn):循環(huán)引用解決不了

可達(dá)性分析法

從GC roots開始向下搜索,搜索所走的路徑叫做引用鏈,當(dāng)一個(gè)對(duì)象到Gc Roots沒有任何引用鏈相連,則證明此對(duì)象可以被回收;

GC roots根節(jié)點(diǎn):線程棧中本地變量,靜態(tài)變量,本地方法棧的變量等等

3)在Java中,對(duì)象什么時(shí)候可以被垃圾回收

當(dāng)對(duì)象對(duì)當(dāng)前使用這個(gè)對(duì)象的應(yīng)用程序變得不可觸及的時(shí)候,這個(gè)對(duì)象就可以被回收了

gc roots向下搜索,沒有任何引用鏈

4)永久代中會(huì)發(fā)生垃圾回收?

不會(huì)發(fā)生在永久代,但是永久代滿了或超過臨界值,會(huì)觸發(fā)垃圾回收機(jī)制,但是永久代也是會(huì)被回收的

5) JVM 有哪些垃圾回收算法

標(biāo)記清除算法

顧名思義,標(biāo)記無(wú)用對(duì)象,然后再進(jìn)行清楚回收,

缺點(diǎn):標(biāo)記清除效率低,無(wú)法清除垃圾碎片,會(huì)產(chǎn)生不連續(xù)內(nèi)存碎片

復(fù)制算法

它把內(nèi)存空間分成兩個(gè)相等的區(qū)域,每次只使用其中一個(gè)區(qū)域,垃圾收集時(shí),遍歷當(dāng)前使用區(qū)域,把存活對(duì)象復(fù)制到另外一個(gè)區(qū)域中,然后將可用的數(shù)據(jù)回收

缺點(diǎn):可用內(nèi)存大小縮小為原來(lái)的一半,對(duì)象存活率高時(shí)會(huì)頻繁經(jīng)行復(fù)制。

標(biāo)記整理法

復(fù)制算法,不太適用于老年代,老年代的存活率較高,這樣會(huì)有較多的復(fù)制操作,導(dǎo)致效率變低,

缺點(diǎn):需要局部調(diào)動(dòng),效率低

分代收集算法

當(dāng)前商業(yè)虛擬機(jī)都采用分代收集算法,將存活周期劃分,年輕代,老年代和永久代

[圖片上傳失敗...(image-f4628-1585402664191)]

6)JVM中有哪些垃圾回收器

serial收集器(復(fù)制算法)

新生代單線程收集器,標(biāo)記清理都是單線程,簡(jiǎn)單高效

ParNew收集器(復(fù)制算法)

serial收集器多線程版本

serial old收集器(標(biāo)記整理)

老年代收集器,單線程

parallel old收集器

老年代收集器,并行

CMS收集器(標(biāo)記)

老年代并行收集器,犧牲系統(tǒng)的吞吐量來(lái)追求收集速度

采用標(biāo)記清除算法,會(huì)產(chǎn)生大量?jī)?nèi)存碎片

場(chǎng)景:使用于延時(shí)要求高的服務(wù),用戶線程不允許長(zhǎng)時(shí)間停頓。

g1(標(biāo)記整理)

garbagr first,面向服務(wù)端應(yīng)用

堆回收器,jdk1.7提供的新收集器,

7)簡(jiǎn)述分代垃圾回收器工作?

分代回收算法.jpg

分代垃圾分兩個(gè)分區(qū):新生代(1/3)和老生代(2/3),

新生代一般采用復(fù)制算法,新生代分三個(gè)分區(qū):Eden(8),from survivor (1),to survivor(1)

首先新建的對(duì)象一般放在eden和form survivor中,存活的對(duì)象放在to survivor中,

清空from survivor和eden區(qū)

from to互換

每次從from 移動(dòng)到to,年齡+1,當(dāng)超過15時(shí),放入老生代(大對(duì)象直接放入老生代)

當(dāng)老生代空間占用達(dá)到某個(gè)值后,就會(huì)觸發(fā)垃圾回收

如果一批對(duì)象的總大小大域survivor>50%時(shí),直接進(jìn)入老年區(qū),老年區(qū)滿時(shí),會(huì)進(jìn)行full gc

(1) STW

stop the word,停止用戶線程

7.java內(nèi)存分配,回收策略,以及minor gc和major gc

1)內(nèi)存分配

對(duì)象的內(nèi)存分配一般是在堆上,自動(dòng)內(nèi)存分配

對(duì)象優(yōu)先分配再eden區(qū)

大對(duì)象直接分配在老年代(大對(duì)象指需要大量連續(xù)內(nèi)存空間)

長(zhǎng)期存活的對(duì)象放入老年代

2)minor gc和Major gc

當(dāng)新生對(duì)象無(wú)法為其分配內(nèi)存時(shí),執(zhí)行minor gc,發(fā)生在新生代

major gc清理老年代,major gc執(zhí)行前往往會(huì)執(zhí)行一次 minor gc

full gc老年代和新生代,

觸發(fā)條件:

老年代空間不足,方法去空間不足,System.gc,minor gc后進(jìn)入老年代的平均大小大于老年代可用大小

裝載->驗(yàn)證->準(zhǔn)備->解析->初始化->實(shí)例化->垃圾收集->對(duì)象終結(jié)->卸載類型

8.java類加載機(jī)制

虛擬機(jī)將描述的類信息從class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行檢驗(yàn),解析和初始化,形成被虛擬機(jī)直接使用java類型

1)什么是類加載器

通過類的全限定名,獲取該類的二進(jìn)制字節(jié)流的代碼塊,加載到內(nèi)存,獲取class類對(duì)象

2)有哪些類加載器

啟動(dòng)類加載器

用于加載java核心類庫(kù),無(wú)法被java程序直接引用

擴(kuò)展類加載器

java擴(kuò)展庫(kù),

系統(tǒng)類加載器

根據(jù)java應(yīng)用的類路徑來(lái)加載Java類,一般來(lái)說,Java應(yīng)用的類都是由它來(lái)實(shí)現(xiàn)加載

用戶自定義類加載器

通過繼承java.lang.ClassLoader的方式來(lái)實(shí)現(xiàn)

3)類加載的執(zhí)行過程

加載

根據(jù)路徑查找相應(yīng)的class文件導(dǎo)入

驗(yàn)證

檢查加載class文件的正確性

準(zhǔn)備

給類的靜態(tài)變量分配內(nèi)存空間

解析

將常量池中符號(hào)引用替換成直接引用 (符號(hào)引用只是一個(gè)表示,直接引用指向內(nèi)存地址)

初始化

對(duì)靜態(tài)變量和靜態(tài)代碼塊執(zhí)行初始化工作

4)什么是雙親委派模型?

類加載器 通過全限定名將class文件加載到j(luò)vm中,然后轉(zhuǎn)化成class對(duì)象

定義

當(dāng)一個(gè)類收到類加載請(qǐng)求時(shí),不會(huì)自己先去加載這個(gè)類,而是將其委派給父類,有父類去加載,如果此時(shí)父類不能加載,反饋給子類,由子類去完成加載

9.jvm調(diào)優(yōu)

1)調(diào)優(yōu)工具

jdk bin目錄下,

jconsole和jvisualvm

2)調(diào)優(yōu)參數(shù)配置

  • -Xms2g:初始化推大小為 2g;

  • -Xmx2g:堆最大內(nèi)存為 2g;

  • -Xmn:年輕代內(nèi)存大小

  • -XX:NewRatio=4:設(shè)置年輕的和老年代的內(nèi)存比例為 1:4;

  • -XX:SurvivorRatio=8:設(shè)置新生代 Eden 和 Survivor 比例為 8:2;

  • –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器組合;

  • -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器組合;

  • -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器組合;

  • -XX:+PrintGC:開啟打印 gc 信息;

  • -XX:+PrintGCDetails:打印 gc 詳細(xì)信息

3)調(diào)優(yōu)方案

億級(jí)電商系統(tǒng)VM參數(shù)設(shè)置優(yōu)化

6.對(duì)象內(nèi)存布局

對(duì)象頭

第一部分:存儲(chǔ)對(duì)象自身運(yùn)行時(shí)的數(shù)據(jù),如哈希碼 gc分代年齡 鎖狀態(tài)標(biāo)志,線程持有的鎖等等

第二部分:類型指針,對(duì)象指向類元數(shù)據(jù)的指針

實(shí)例數(shù)據(jù)

數(shù)據(jù)

對(duì)齊填充

不是必然存在,只是為了對(duì)齊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容