自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

想要徹底搞懂JVM虛擬機(jī),看了這篇就夠了

云計(jì)算 虛擬化
本文從頭讀到尾就是一個(gè)虛擬機(jī)大部分知識(shí)點(diǎn)的框架,就像一顆搜索樹(shù)一樣,我們想要了解哪一部分知識(shí),就從根節(jié)點(diǎn)開(kāi)始搜索,直到找到我們想要了解的知識(shí)所在的葉節(jié)點(diǎn)或者子樹(shù)。

 [[272380]]

引言

本文的使用方法:

本文從頭讀到尾就是一個(gè)虛擬機(jī)大部分知識(shí)點(diǎn)的框架,就像一顆搜索樹(shù)一樣,我們想要了解哪一部分知識(shí),就從根節(jié)點(diǎn)開(kāi)始搜索,直到找到我們想要了解的知識(shí)所在的葉節(jié)點(diǎn)或者子樹(shù)。不過(guò)如果把所有的知識(shí)都在一篇文章中列出來(lái)那文章就太長(zhǎng)啦,很容易把握不住整體框架,所以本文中對(duì)于知識(shí)點(diǎn)的詳細(xì)介紹都以鏈接的形式給出,大家可以通過(guò)本文回憶 JVM 相關(guān)的知識(shí),遇到想不起來(lái)的點(diǎn)可以點(diǎn)開(kāi)相應(yīng)的鏈接查看,這樣像考試一樣的學(xué)習(xí)方式,可以加深我們的印象,記憶效果將遠(yuǎn)遠(yuǎn)好于盯著文字硬背。

Content

  • 說(shuō)說(shuō) Java 的內(nèi)存管理機(jī)制
  • 說(shuō)說(shuō) Java 虛擬機(jī)程序執(zhí)行
  • 說(shuō)說(shuō)虛擬機(jī)性能監(jiān)控及故障處理
  • 說(shuō)說(shuō) JIT 優(yōu)化
  • 說(shuō)說(shuō) Java 的內(nèi)存模型(JMM)
  • 項(xiàng)目推薦

說(shuō)說(shuō) Java 的內(nèi)存管理機(jī)制

和 C++ 相比,Java 的內(nèi)存管理機(jī)制可謂是一大特色,程序員們不需要自己去寫(xiě)代碼手動(dòng)釋放內(nèi)存了,甚至你想自己干虛擬機(jī)都不給你干這個(gè)事情的機(jī)會(huì)(就是說(shuō),我們是沒(méi)有辦法自動(dòng)觸發(fā) GC 的),虛擬機(jī)全權(quán)包辦了 Java 的內(nèi)存控制權(quán)力。這看起來(lái)挺美好的,不過(guò)也意味著,一旦虛擬機(jī)疏忽了(感覺(jué)不能賴虛擬機(jī),畢竟虛擬機(jī)也不知道你能把程序?qū)懗赡菢影?hellip;…),發(fā)生了內(nèi)存泄漏,問(wèn)題都不好查,所以知道虛擬機(jī)到底是怎么管的內(nèi)存就十分重要啦。

虛擬機(jī)對(duì)內(nèi)存的管理,其實(shí)就是收拾哪些存放我們不會(huì)再用的對(duì)象的內(nèi)存,把它們清了拿來(lái)放新的對(duì)象。所以它首先需要研究下以下幾個(gè)問(wèn)題:

  • 這堆報(bào)廢了的對(duì)象到底被放哪了?(Java 堆和方法區(qū))
  • 5 個(gè)數(shù)據(jù)區(qū)域:程序計(jì)數(shù)器、Java 虛擬機(jī)棧、本地方法棧、Java 堆、方法區(qū)。
  • 這堆放報(bào)廢對(duì)象的地方會(huì)不會(huì)內(nèi)存泄漏?或者換一個(gè)洋氣點(diǎn)的叫法,會(huì)不會(huì) OOM?(每個(gè)區(qū)的 OOM)
  • 對(duì)象是咋被放到這些地方的?(堆中對(duì)象的創(chuàng)建)
  • 對(duì)象被安置好了之后虛擬機(jī)怎么再次找到它?(堆中對(duì)象的訪問(wèn))

知道對(duì)象都放哪了,虛擬機(jī)就知道去哪里找報(bào)廢的對(duì)象了,接下來(lái)就涉及到了 Java 的一大超級(jí)特色:垃圾收集(GC)了,垃圾收集,正如其名,就是把這些報(bào)廢的對(duì)象給清了,騰出來(lái)地方放新對(duì)象,它主要關(guān)心以下幾個(gè)事情:

  • 哪些內(nèi)存需要回收?
  • 放對(duì)象的地方需要垃圾回收:Java 堆和方法區(qū)。
  • 什么時(shí)候回收?(判斷對(duì)象的生死)
  • 判斷對(duì)象報(bào)廢了沒(méi)的算法(重點(diǎn)):引用計(jì)數(shù)法 和 可達(dá)性分析法。
  • 如何回收?
  • GC 算法原理(垃圾收集算法)
  • 基礎(chǔ):標(biāo)記 - 清除算法
  • 解決效率問(wèn)題:復(fù)制算法
  • 解決空間碎片問(wèn)題:標(biāo)記 - 整理算法
  • 進(jìn)化:分代收集算法
  • GC 算法的真正實(shí)現(xiàn):
  • 7 個(gè)葫蘆娃,哦不,垃圾收集器
  • 新生代:Serial、ParNew、Parallel Scavenge
  • 老年代:Serial Old、Parallel Old、CMS
  • 全能:G1
  • HotSpot 虛擬機(jī)如何高效實(shí)現(xiàn) GC 算法

說(shuō)完了對(duì)象是怎么被回收的,現(xiàn)在才算是把 Java 的內(nèi)存管理機(jī)制需要用到的小零件給補(bǔ)全了。也就是說(shuō),Java 的內(nèi)存管理流程應(yīng)該是這樣滴:

根據(jù)新對(duì)象是什么對(duì)象給對(duì)象找個(gè)地放

發(fā)現(xiàn)內(nèi)存中沒(méi)地放這個(gè)新對(duì)象了就進(jìn)行 GC 清理出來(lái)點(diǎn)地方

真找不著地了就拋 OOM ……

虛擬機(jī)一般都用的是進(jìn)化版的 GC 算法,也就是分代收集算法,也就是說(shuō),虛擬機(jī) Java 堆中的內(nèi)存是分為新生代和老年代的,那么給新對(duì)象找地方放的時(shí)候放哪呢?具體怎么放呢?放好了之后的對(duì)象會(huì)不會(huì)換個(gè)地呆呀?GC 什么時(shí)候進(jìn)行?清理哪呢?……預(yù)知 Java 的內(nèi)存管理機(jī)制的詳情如何,可以看看我的往期文章。

到此為止,Java 的內(nèi)存管理機(jī)制也就說(shuō)的差不多了?,F(xiàn)在,我們已經(jīng)知道一個(gè)對(duì)象是如何在虛擬機(jī)的操控下,在內(nèi)存中走一遭的了。可是首先,對(duì)象肯定是根據(jù)我們寫(xiě)的類創(chuàng)建的,那么我們寫(xiě)的類到底是如何變?yōu)閮?nèi)存中的對(duì)象的呢?而且,我們創(chuàng)建對(duì)象當(dāng)然是為了執(zhí)行它里面的方法呀,那么這個(gè)方法是怎么被執(zhí)行的呢?想要回答這些問(wèn)題,就需要我們研究一下 Java 虛擬機(jī)是如何執(zhí)行我們的程序的了。

說(shuō)說(shuō) Java 虛擬機(jī)程序執(zhí)行

想要執(zhí)行 Java 程序,必然要先將 Java 代碼編譯成字節(jié)碼文件,也就是 Class 文件,這個(gè)編譯的過(guò)程我們暫且不談,主要說(shuō)一下如果執(zhí)行這個(gè) Class 文件,所以首先我們要先來(lái)了解一下 Class 文件的組成結(jié)構(gòu)。

在了解了組成結(jié)構(gòu)之后,接下來(lái)需要考慮的事情是,我們?cè)撛趺窗堰@個(gè) .class 文件加載進(jìn)內(nèi)存,讓它變成方法區(qū)(Java 8 后變?yōu)榱?Metaspace 元空間)的一個(gè) Class 對(duì)象呢?(類的加載)。

虛擬機(jī)的類加載機(jī)制說(shuō)頭可就多了,大家都喜歡揪著這問(wèn),其實(shí)主要就下面這 3 個(gè)過(guò)程:

  • 類加載的時(shí)機(jī):在程序第一次主動(dòng)引用類的時(shí)候。
  • 什么是主動(dòng)引用和被動(dòng)引用?
  • 什么是顯式加載和隱式加載?
  • 類的生命周期:加載 —— 驗(yàn)證 —— 準(zhǔn)備 —— 解析 —— 初始化 —— 使用 —— 卸載
  • 類加載器
  • 如何判斷兩個(gè)類 “相等”?
  • 類加載器的分類?
  • 什么雙親委派模型?
  • 破壞雙親委派模型?
  • 實(shí)現(xiàn) Java 類的熱替換
  • 如何自定義類加載器?
  • 需要保留雙親委派模型:extends ClassLoader,重寫(xiě) findClass()
  • 破壞雙親委派模型:直接重寫(xiě) loadClass()

將類加載到內(nèi)存之后,接下來(lái)就要考慮如何執(zhí)行這個(gè)類中的方法了。我們知道 5 大內(nèi)存區(qū)域中的 Java 虛擬機(jī)棧是服務(wù)與 Java 方法的內(nèi)存模型,那么我們首先應(yīng)該了解一下 虛擬機(jī)棧的棧幀到底是怎樣的結(jié)構(gòu),虛擬機(jī)棧的棧幀結(jié)構(gòu)包括如下幾個(gè)部分:

  • 局部變量表(重要)
  • 操作數(shù)棧 & 動(dòng)態(tài)連接 & 方法返回地址

了解了輔助方法執(zhí)行的 Java 虛擬機(jī)棧的結(jié)構(gòu)后,接下來(lái)就要考慮 Java 類中方法的調(diào)用了。就像將大象放進(jìn)冰箱,方法的調(diào)用也不是上來(lái)就之間執(zhí)行方法的,而是分為以下兩個(gè)步驟:

  • 方法調(diào)用:確定被調(diào)用的方法是哪一個(gè)
  • 基于棧的解釋執(zhí)行:真正的執(zhí)行方法的字節(jié)碼

為什么還要加一個(gè)方法調(diào)用的步驟呢?因?yàn)橐磺蟹椒ㄕ{(diào)用都是在 Class 文件中以常量池中的符號(hào)引用存儲(chǔ)的,這就導(dǎo)致了不是我們想要執(zhí)行哪個(gè)方法就能立刻執(zhí)行的,因?yàn)槲覀兪紫刃枰鶕?jù)這個(gè)符號(hào)引用(其實(shí)就一字符串)找到我們想要執(zhí)行的方法,而這一過(guò)程就叫做方法調(diào)用。當(dāng)找到這個(gè)方法之后,我們才會(huì)開(kāi)始執(zhí)行這個(gè)方法,也就是基于棧的解釋執(zhí)行。

想要調(diào)用一個(gè)方法,我們先來(lái)看一下虛擬機(jī)中有哪些指令可以進(jìn)行方法調(diào)用:方法調(diào)用字節(jié)碼指令。

這些字節(jié)碼會(huì)觸發(fā)不同的方法調(diào)用,總體來(lái)說(shuō),有以下幾種:

  • 解析調(diào)用
  • 分派調(diào)用(沒(méi)有在解析調(diào)用中將符號(hào)引用轉(zhuǎn)化為直接引用的方法就只能靠分派調(diào)用了)
  • 靜態(tài)分派(方法重載)
  • 動(dòng)態(tài)分派(方法重寫(xiě))

確定了要調(diào)用的方法具體是哪一個(gè)了之后,就可開(kāi)始基于棧的解釋執(zhí)行了,這個(gè)時(shí)候,方法才真正的被執(zhí)行。

此外,還需要了解一下 Java 的動(dòng)態(tài)類型語(yǔ)言支持。

說(shuō)說(shuō)虛擬機(jī)性能監(jiān)控及故障處理

常用的 JDK 命令行工具:JDK 命令行工具。

JVM 常見(jiàn)的參數(shù)設(shè)置已經(jīng)設(shè)置經(jīng)驗(yàn)可見(jiàn):JVM 常見(jiàn)參數(shù)設(shè)置。

虛擬機(jī)調(diào)優(yōu)案例分析可見(jiàn):虛擬機(jī)調(diào)優(yōu)案例分析。

說(shuō)說(shuō) JIT 優(yōu)化

JIT (Just In Time),也就是即時(shí)編譯,首先我們需要知道 什么是 JIT?

然后,對(duì)于 HotSpot 虛擬機(jī)內(nèi)的即時(shí)編譯器運(yùn)作過(guò)程,我們可以通過(guò)以下 5 個(gè)問(wèn)題來(lái)研究它:

  • 為什么要使用解釋器與編譯器并存的架構(gòu)?
  • 為什么虛擬機(jī)要實(shí)現(xiàn)兩個(gè)不同的 JIT 編譯器?
  • 什么是虛擬機(jī)的分層編譯?
  • 如何判斷熱點(diǎn)代碼,觸發(fā)編譯?
  • 什么是熱點(diǎn)代碼?(兩種)
  • 什么是 “多次” 執(zhí)行?
  • HotSpot 采用的是基于計(jì)數(shù)器的熱點(diǎn)探測(cè)方法,并且為了對(duì)兩種熱點(diǎn)代碼進(jìn)行探測(cè),每個(gè)方法有 2 個(gè)計(jì)數(shù)器
  • 方法調(diào)用計(jì)數(shù)器
  • 回邊計(jì)數(shù)器
  • HotSpot 熱點(diǎn)代碼探測(cè)流程
  • 熱點(diǎn)代碼編譯的過(guò)程?

此外,JIT 并不是簡(jiǎn)單的將熱點(diǎn)代碼編譯成機(jī)器碼就收工的,它還會(huì)對(duì)代碼的執(zhí)行進(jìn)行優(yōu)化,主要有以下幾種經(jīng)典的優(yōu)化技術(shù):

  • 公共子表達(dá)式消除【語(yǔ)言無(wú)關(guān)】
  • 數(shù)組范圍檢查消除【語(yǔ)言相關(guān)】
  • 方法內(nèi)聯(lián)【最重要】
  • 逃逸分析【最前沿】

說(shuō)說(shuō) Java 的內(nèi)存模型(JMM)

這部分內(nèi)容主要與并發(fā)編程的內(nèi)容相關(guān),所以詳細(xì)介紹會(huì)跳到另一個(gè) repo:Java-Concurrency-in-Practice。

Java 的內(nèi)存模型主要就是研究一個(gè)變量的值是怎么在主內(nèi)存、線程的工作內(nèi)存和 Java 線程(執(zhí)行引擎)之間倒騰的。就是說(shuō)雖然 Java 內(nèi)存模型規(guī)定了所有變量都存儲(chǔ)在主內(nèi)存中,但是每個(gè)線程都有一個(gè)自己的工作內(nèi)存,里面存著從主內(nèi)存拷貝來(lái)的變量副本,Java 線程要對(duì)變量進(jìn)行修改,都是先在自己的工作內(nèi)存中進(jìn)行,然后再把變化同步回主內(nèi)存中去。

這樣做是由于計(jì)算機(jī)的存儲(chǔ)設(shè)備和處理器的運(yùn)算速度有著幾個(gè)數(shù)量級(jí)的差距,所以需要在主內(nèi)存和 Java 線程間加入一個(gè)工作內(nèi)存作為緩沖,但這也同時(shí)會(huì)導(dǎo)致主內(nèi)存和工作內(nèi)存間的緩存一致性問(wèn)題,所以當(dāng)兩個(gè)工作內(nèi)存中關(guān)于同一個(gè)變量的值發(fā)生沖突時(shí),需要一定的訪問(wèn)規(guī)則來(lái)確定主內(nèi)存以怎樣的順序同步這個(gè)變量,也就是說(shuō)該聽(tīng)哪個(gè)工作內(nèi)存的。而 Java 的內(nèi)存模型的主要目標(biāo)就是定義這個(gè)規(guī)則,即虛擬機(jī)如何將變量存儲(chǔ)到內(nèi)存或是從內(nèi)存中取出的。

簡(jiǎn)單的來(lái)講,就是掌握 Java 內(nèi)存模型中的 8 個(gè)原子操作,并且知道 Java 內(nèi)存間是如何通過(guò)這 8 個(gè)操作進(jìn)行變量傳遞的。

其實(shí) Java 的內(nèi)存模型就是圍繞著在并發(fā)的過(guò)程中如何處理 原子性、可見(jiàn)性、有序性 這 3 個(gè)特征建立的。同時(shí) Java 除了可以依靠 volatile 和 synchronized 來(lái)保證有序性外,它自己本身還有一個(gè) Happens-Before 原則,依靠這個(gè)原則,我們就可以判斷并發(fā)環(huán)境下的兩個(gè)操作是否可能存在沖突了。

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2018-09-11 14:47:51

面試Java虛擬機(jī)

2024-07-05 11:01:13

2020-09-09 12:55:28

Nginx高并發(fā)性能

2020-09-10 09:31:34

Nginx HTTP代理服務(wù)器

2022-02-22 08:55:29

SelectPoll/ Epoll

2022-04-07 13:02:53

前端緩存

2017-03-30 22:41:55

虛擬化操作系統(tǒng)軟件

2019-07-10 15:15:23

JVM虛擬機(jī)Java

2010-09-17 15:12:57

JVMJava虛擬機(jī)

2025-02-14 08:53:24

2021-09-30 07:59:06

zookeeper一致性算法CAP

2022-03-13 09:31:43

MQ消息隊(duì)列ActiveMQ

2019-08-16 09:41:56

UDP協(xié)議TCP

2020-05-08 16:55:48

Java虛擬機(jī)JVM

2011-06-22 13:35:55

JVM

2015-11-02 09:49:04

Android屏幕適配官方指導(dǎo)

2021-10-13 16:54:22

IPv6網(wǎng)絡(luò)5G

2021-09-02 07:00:32

鑒權(quán)Web 應(yīng)用Cookie-sess

2022-03-29 08:23:56

項(xiàng)目數(shù)據(jù)SIEM

2019-10-31 09:48:53

MySQL數(shù)據(jù)庫(kù)事務(wù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)