JVM學習筆記

JVM基本結(jié)構(gòu)

jvm基本結(jié)構(gòu)

PC寄存器

  • 每個線程擁有一個PC寄存器
  • 線程創(chuàng)建時創(chuàng)建PC寄存器
  • 指向下一條指令的地址
  • 執(zhí)行本地方法時巴帮,PC的值是undefind

方法區(qū):用來保存類的一些元信息的(例外意敛,jdk1.7String的常量信息已經(jīng)移到了堆)

  • 類的常量池
  • 字段方法信息
  • 方法字節(jié)碼
  • 通常和永久區(qū)(Perm關(guān)聯(lián)在一起)
    永久區(qū)并不是永久不變的畅铭,只是相對的穩(wěn)定

  • 和程序開發(fā)密切相關(guān)
  • 應用程序?qū)ο蠖急4嬖趈ava堆中
  • 所有線程共享java堆
  • 對于GC來說卷雕,堆也是分代的
  • GC的主要工作區(qū)間

桟:

  • 線程私有的
  • 由一系列幀組成(因此java桟也叫做幀桟)
  • 幀保存一個方法的局部變量介汹,操作數(shù)桟棍辕,常量池指針
  • 每一次方法調(diào)用創(chuàng)建一個幀,并壓桟


    圖片.png

    reference this 類比于python中的成員方法必須傳self

操作數(shù)桟

圖片.png

桟上分配

  • 小對象(一般幾十個bytes)席函,在沒有逃逸(這個對象在其他線程也會使用到)的情況下铐望,可以直接分配在桟上。
  • 直接分配在桟上茂附,可以自動回收正蛙,減輕GC壓力
  • 大對象或者逃逸對象無法再桟上分配。

堆营曼、桟乒验、方法區(qū)的交互

圖片.png

java的內(nèi)存模型

  • 每個線程中有一個工作內(nèi)存和主存獨立
  • 工作內(nèi)存存放主存中變量的拷貝
  • 可見性:一個線程修改了某個變量,其他線程立即知道
  • 有序性:
    在本線程內(nèi)蒂阱,操作都是有序的
    在線程外觀察徊件,操作都是無序的(指令重排或主內(nèi)存同步延時)

編譯和解釋運行的概念

  • 解釋執(zhí)行:
    解釋執(zhí)行以解釋方式運行字節(jié)碼
    解釋執(zhí)行的意思是:讀一句執(zhí)行一句
  • 編譯運行(JIT):
    將字節(jié)碼編譯成機器碼
    直接執(zhí)行機器碼
    運行時編譯
    編譯后性能有數(shù)量級的提升

GC的概念

  • 全稱Garbage Collection
  • 1960 List語言首先使用GC
  • java中奸攻,GC管理堆空間和永久區(qū)

GC算法

引用計數(shù)法

  • 概念:通過引用計算來回收垃圾
  • 使用者:COM,Python虱痕,ActionScript3
  • 原理:
    引用計數(shù)器的實現(xiàn)很簡單,對于一個對象A,只要有任何一個對象引用了A,則A的引用計數(shù)器就 加1,當引用失效時,引用計數(shù)器就減1睹耐。只要對象A的引用計數(shù)器的值為0,則對象A就不可能再被使用。
  • 缺點:引用和去引用伴隨著加法和減法部翘,影響性能
  • 很難處理循環(huán)引用(垃圾對象的循環(huán)引用硝训,也就是那三個點不會被回收)


    圖片.png

標記清除法

  • 原理:
    將垃圾回收分為兩個階段:標記階段和清除階段。在標記階段新思,首先通過根節(jié)點窖梁,標記所有從根節(jié)點開始的可達對象,因此夹囚,未標記對象就是未引用的垃圾對象纵刘,然后在清除階段清除所有未標記的對象。
  • 適用場合:適用于存活對象較多的場合荸哟,如老年代假哎。

標記壓縮法

  • 原理
    它在標記清除法的基礎(chǔ)上做了一些優(yōu)化。和標記清除法一樣鞍历,標記壓縮算法也是從根節(jié)點開始舵抹,對所有的對象做一次標記。但之后劣砍,它并不是簡單的清理未標記的對象惧蛹,而是將所有的的存活對象壓縮到內(nèi)存的一端,之后清理邊界外的所有空間刑枝。
  • 優(yōu)勢:
    能夠整理內(nèi)存碎片香嗓,避免分配大對象時,空間不夠?qū)е翭ullGC
  • 適用場合:適用于存活對象較多的場合装畅,如老年代陶缺。

復制算法

  • 原理:
    將原有的內(nèi)存分為兩塊,每次只是用其中一塊洁灵,在垃圾回收時饱岸,將正在使用的內(nèi)存中的存活對象復制到未使用的內(nèi)存塊中,之后清除正在使用的內(nèi)存塊中的所有對象徽千,交換兩個內(nèi)存的角色苫费,完成垃圾回收
  • 優(yōu)點:與標記清除法相比,復制算法是一種相對高效的回收算法
  • 缺點:浪費空間
  • 適用場合:適用于存活對象較少的場合双抽,如新生代百框。

復制算法的優(yōu)化:整合標記清除思想

image.png
  • 當垃圾回收進行的時候,大對象進入擔彪剐冢空間(因為復制空間一般不大)
  • 老年對象(好幾次回收都沒有被回收掉的對象)進入老年代

可觸及性

可觸及的:

從根節(jié)點可以觸及到這個對象

可復活的:

一旦所有引用被釋放铐维,就是可復活狀態(tài)柬泽,因為在finalize()中可能復活該對象

不可觸及

  • 在finalize()之后,可能會進入不可觸及狀態(tài)
  • 不可觸及狀態(tài)不可能復活
  • 可以回收


    圖片.png

    第一次GC調(diào)用finalize()方法嫁蛇,因為覆寫了finalize()方法锨并,復活了obj,所以第一次obj不是nul睬棚,finalize()方法只會被調(diào)用一次第煮,第二次gc,obj就不能復活了

  • 桟中引用的對象
  • 方法區(qū)中靜態(tài)成員或者常量的引用 (全局對象)
  • JNI方法桟中的引用對象

Stop-The-World

  • java中的一種全局停頓現(xiàn)象
  • 全局停頓抑党,所有java代碼停止包警,native可以執(zhí)行,但不能和jvm交互
  • 多半由于GC引起
  • 原因:類比一邊開party底靠,一邊打掃衛(wèi)生害晦,只能讓大家停下來才能掃干凈。
  • 危害:長時間服務停止暑中,沒有響應壹瘟;遇到HA系統(tǒng),可能引起主備切換痒芝,嚴重危害環(huán)境。

GC參數(shù)

串行收集器(GC線程只有一個)

最古老牵素,最穩(wěn)定严衬,效率高,可能產(chǎn)生較長的停頓
-XX:+UseSerialGC:
新生代笆呆、老年代使用串行回收
新生代使用復制算法请琳,老年代使用標記壓縮算法

并行收集器(GC線程有多個)

ParNew:

  • -XX:+UseParNewGC:
  • 新生代并行,老年代還是串行
  • -XX:+ParallelGCThreads 限制線程數(shù)量

Parallel收集器

  • 類似ParNew
  • 新生代復制算法
  • 老年代標記壓縮算法
  • 更加關(guān)注吞吐量
  • -XX:+UseParallelGC
    老年代串行
  • -XX:+UseParallelOldGC
    老年代并行
  • XX:MaxGCPauseMills
    最大停頓時間
  • XX:GCTimeRatio
    0-100取值范圍
    垃圾收集時間占總時間比
    默認99,即最大允許1%時間做GC
  • 兩個參數(shù)是矛盾的。因為停頓時間和吞吐量不可能同時調(diào)優(yōu)

CMS收集器

  • Concurrent Mark Sweep 并發(fā)標記清除(并發(fā)指的是和應用程序一起執(zhí)行)
  • 標記清除算法
  • 并發(fā)階段會降低吞吐量
  • 老年代收集器(新生代使用ParNew)
  • XX:+UseConcMarkSweepGC
  • 停頓時間較少
    -過程比較復雜
    初始標記:根可以直接關(guān)聯(lián)到的對象赴恨,速度快
    并發(fā)標記(和用戶線程一起):主要標記過程足删,標記全部對象
    重新標記:由于并發(fā)標記時,用戶線程依然運行休里,因此在正式清理前,再做修正
    并發(fā)清理(和用戶線程一起)基于標記結(jié)果,直接清理對象


    CMS收集器
  • 清理不徹底
  • 不能在空間快滿的時候清理
  • -XX:CMSInitiatingOccupancyFraction設(shè)置觸發(fā)GC的閾值
  • 如果不幸預留的空間不夠圾旨,就會引起concurrent mode failure


    CMS不用標記壓縮但是也會使用命令進行整理碎片

GC參數(shù)整理

GC參數(shù)整理

GC參數(shù)整理

類裝載器

class轉(zhuǎn)載驗證流程

加載

  • 裝載類的第一個階段
  • 取得類的二進制流
  • 轉(zhuǎn)為方法區(qū)數(shù)據(jù)結(jié)構(gòu)
  • 在java堆中生成對應的java.Lang.Class對象

鏈接

  • 驗證:
    目的是保證Class流的格式正確
    文件格式驗證:
    ? ? ? ?是否以0xCAFEBABE開頭
    ? ? ? ?版本號是否合理
    元數(shù)據(jù)驗證:
    ? ? ? ?是否有父類
    ? ? ? ?是否繼承了final類
    ? ? ? ?非抽象類實現(xiàn)了所有抽象方法
    字節(jié)碼驗證(很復雜):
    ? ? ? ?運行檢查
    ? ? ? ?桟數(shù)據(jù)類型和操作碼數(shù)據(jù)是否吻合
    ? ? ? ?跳轉(zhuǎn)指令指定到合理的位置
    符號引用驗證:
    ? ? ? ?常量池描述類是否存在
    ? ? ? ?訪問的方法或字段是否存在且足夠的權(quán)限
  • 準備:
    分配內(nèi)存,并為類設(shè)置初始值(方法區(qū)中)
    ? ? ? ?public static int v=1
    ? ? ? ?在準備階段魏蔗,v會被設(shè)置為0
    ? ? ? ?在初始化的<clinit>中才會被設(shè)置為1
    ? ? ? ?對于static final類型砍的,在準備階段就會被賦值
  • 解析:
    將符號引用替換為直接引用
    符號引用:字符串,引用對象不一定被加載莺治。就是一個類的字符串表現(xiàn)廓鞠,比如說"java.lang.Object"
    直接引用:指針或地址偏移量帚稠,引用對象一定在內(nèi)存

初始化

  • 執(zhí)行類的構(gòu)造器<clinit>
    static 變量 賦值語句
    static{}語句
  • 子類的<clinit>調(diào)用前保證父類的<clinit>被調(diào)用
  • <clinit>是線程安全的

什么是ClassLoader

  • ClassLoader是一個抽象類
  • ClassLoader的實例將讀入java字節(jié)碼然后將類裝載到jvm中
  • CLassLoader可以定制,滿足不懂的字節(jié)碼流獲取方式
  • ClassLoader負責類裝載過程的加載階段
  • 一些重要方法


    ClassLoader的重要方法
  • ClassLoader的加載順序


    圖片.png

自底向上查詢類是否已經(jīng)加載床佳,自頂向下嘗試加載類滋早。
我們寫的類一般都是在App ClassLoader中加載的,如果要查詢一個類是否已經(jīng)被加載夕土,先從App ClassLoader中查找馆衔,找不到再網(wǎng)上找。如果要加載一個類怨绣,先問一下Bootstrap ClassLoader有沒有角溃,沒有再往下走。
雙親模式的問題
BootstrapLoader不能查找App ClassLoader中的類
解決方法:Thread.setContextClassLoader()
這是一個上下文加載器篮撑,是一個角色减细,用以頂層ClassLoader無法訪問底層ClassLoader的問題,基本思想是在頂層ClassLoader中傳入底層ClassLoader實例

java堆的分析

內(nèi)存溢出(OOM)的原因

  • 在jvm中的內(nèi)存區(qū)間劃分
    堆赢笨,永久區(qū)未蝌,線程桟,直接內(nèi)存
  • 占用大量堆空間茧妒,直接溢出
  • 永久區(qū)溢出萧吠,可以增大Perm區(qū)大小,運行Class回收
  • java棧溢出
    這里的桟指的是在創(chuàng)建線程的時候桐筏,需要為線程分配桟空間纸型,這個桟空間是向操作系統(tǒng)請求的,如果操作系統(tǒng)無法給出足夠的空間梅忌,就會拋出OOM狰腌。解決辦法:減少堆內(nèi)存,減少線程桟的大小

Mark Word牧氮,對象頭標記 32位

描述對象的hash琼腔,鎖信息,垃圾回收的年齡踱葛,標記
指向鎖記錄的指針
指向monitor的指針
GC標志
偏向鎖線程ID

偏向鎖

  • 大部分情況下是沒有競爭的丹莲,所以可以通過偏向來提高性能
  • 所謂的偏向,就是偏心尸诽,即鎖會偏向于當前已經(jīng)占有的鎖的線程
  • 將對象投Mark的標記設(shè)置為偏向圾笨,并將線程ID寫入對象頭
  • 只要沒有競爭,獲得偏向鎖的線程逊谋,在將來進入同步快擂达,不需要做同步
  • 當其他線程請求相同的鎖時,偏向模式結(jié)束
  • 在競爭激烈的場合,偏向鎖會增加系統(tǒng)負擔

輕量級鎖 BasicObjectLock

  • 嵌入在線程桟中對象
    包含兩個部分板鬓,一個是對象頭悲敷,另一個是指向持有這個鎖的對象的指針
  • 普通的鎖處理性能不夠理想,輕量級鎖是一種快速鎖定的方法俭令。
  • 如果對象沒有被鎖定
    將對象頭的Mark指針保存到鎖對象中
    將對象頭設(shè)置為指向鎖的指針(在線程桟空間中)
  • 如果輕量級鎖失敗后德,表示存在競爭,升級為重量級鎖(常規(guī)鎖)
  • 在沒有競爭的前提下抄腔,減少傳統(tǒng)鎖使用OS互斥量產(chǎn)生的性能損耗
  • 在競爭激烈時瓢湃,輕量級鎖會多做很多額外的操作,導致性能下降赫蛇。

自旋鎖

  • 當競爭存在時绵患,如果線程可以很快獲得鎖,那么可以不在OS層掛起線程悟耘,讓線程做幾個空操作(自旋)
  • 如果同步塊很長落蝙,自旋失敗,會降低系統(tǒng)性能
  • 如果同步塊很短暂幼,自旋成功筏勒,節(jié)省線程掛起切換的時間,提升系統(tǒng)性能旺嬉。

獲取鎖的流程

首先嘗試獲取偏向鎖管行,如果可用,進入偏向模式邪媳,如果不可用捐顷,嘗試輕量級鎖,如果可用悲酷,使用輕量級鎖套菜,到此結(jié)束亲善,如果不可用设易,嘗試自旋鎖,如果成功蛹头,那就拿到鎖了顿肺,如果不成功,最后才會膨脹為重量鎖(普通鎖)渣蜗,在操作系統(tǒng)層面進行掛起屠尊。

代碼層面鎖的優(yōu)化

減少鎖的持有時間

盡量使用同步代碼塊而不是同步方法

減小鎖的粒度

  • 將大對象,拆成小對象耕拷,大大增加并行度讼昆,降低鎖競爭
  • 偏向鎖,輕量級鎖成功率更高
  • ConcurrentHashMap
    若干個Segment骚烧,一個Segment維護一個HashEntry浸赫,put操作時闰围,先定為到Segment,鎖定一個Segment既峡,執(zhí)行put
    減小鎖粒度后羡榴,ConcurrentHashMap允許多個線程同時進入

鎖分離

  • 根據(jù)功能分離
  • ReadWriteLock
  • 讀多寫少的情況,可以提高性能

鎖粗化

圖片.png

鎖消除

在即時編譯時运敢,如果發(fā)現(xiàn)不可能被共享的對象校仑,則可以消除這些所的操作

無鎖

  • CAS(Compare And Swap)
  • 非阻塞同步
  • CAS(V,E,N)
  • 應用層面判斷多線程的干擾,如果有干擾,則通知線程重試传惠。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末迄沫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子涉枫,更是在濱河造成了極大的恐慌邢滑,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件愿汰,死亡現(xiàn)場離奇詭異困后,居然都是意外死亡,警方通過查閱死者的電腦和手機衬廷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門摇予,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吗跋,你說我怎么就攤上這事侧戴。” “怎么了跌宛?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵酗宋,是天一觀的道長。 經(jīng)常有香客問我疆拘,道長蜕猫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任哎迄,我火速辦了婚禮回右,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘漱挚。我一直安慰自己翔烁,他們只是感情好,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布旨涝。 她就那樣靜靜地躺著蹬屹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上慨默,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天秃踩,我揣著相機與錄音,去河邊找鬼业筏。 笑死憔杨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蒜胖。 我是一名探鬼主播消别,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼台谢!你這毒婦竟也來了寻狂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤朋沮,失蹤者是張志新(化名)和其女友劉穎蛇券,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體樊拓,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡纠亚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了筋夏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒂胞。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖条篷,靈堂內(nèi)的尸體忽然破棺而出骗随,到底是詐尸還是另有隱情,我是刑警寧澤赴叹,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布鸿染,位于F島的核電站,受9級特大地震影響乞巧,放射性物質(zhì)發(fā)生泄漏涨椒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一摊欠、第九天 我趴在偏房一處隱蔽的房頂上張望丢烘。 院中可真熱鬧柱宦,春花似錦些椒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春石窑,著一層夾襖步出監(jiān)牢的瞬間牌芋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工松逊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留躺屁,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓经宏,卻偏偏與公主長得像犀暑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子烁兰,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

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