《深入理解java虛擬機(jī)》之類加載機(jī)制

類加載機(jī)制

image

類從加載導(dǎo)卸載出內(nèi)存的整個(gè)生命周期如上圖所示策菜。圖中的7個(gè)階段中晶疼,加載、驗(yàn)證又憨、準(zhǔn)備翠霍、初始化和卸載的順序是確定的,而解析和使用階段不一定蠢莺,解析可能在初始化之后(動(dòng)態(tài)綁定)寒匙。

類加載時(shí)機(jī)

有且只有以下5種情況:

  1. 遇到new、getstatic躏将、putstatic锄弱、invokestatic等字節(jié)碼,對(duì)應(yīng)Java代碼中的new對(duì)象祸憋、讀取或者設(shè)置類的靜態(tài)變量会宪、調(diào)用類的靜態(tài)方法;
  2. 使用reflect包進(jìn)行反射的時(shí)候蚯窥;
  3. 初始化類時(shí)掸鹅,若父類未初始化,則先出發(fā)父類的初始化拦赠;
  4. JVM啟動(dòng)時(shí)巍沙,執(zhí)行的主類(包含main()方法的類);
  5. JDK1.7以后動(dòng)態(tài)語(yǔ)言支持矛紫。

注意是有且僅有赎瞎,其他情況,譬如數(shù)組定義引用到未加載的類颊咬、調(diào)用類的靜態(tài)常量(存儲(chǔ)在常量池中)等其他情況并不會(huì)觸發(fā)類的初始化加載务甥。

加載

完成以下事情:

  1. 通過(guò)類的全限定名獲取類的二進(jìn)制字節(jié)流(不一定從文件獲取,也可能是從網(wǎng)絡(luò)喳篇、zip包敞临、動(dòng)態(tài)代理、其他文件如jsp等途徑生成)麸澜;
  2. 將字節(jié)流的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)挺尿,具體由虛擬機(jī)自行實(shí)現(xiàn)定義;
  3. 生成對(duì)應(yīng)java.lang.Class對(duì)象,放在方法區(qū)编矾。

數(shù)組類本身不通過(guò)類加載器創(chuàng)建熟史,而是JVM直接創(chuàng)建的,如果數(shù)組類加載的時(shí)候窄俏,其組件類型(去掉最外面維度之后的類型)是引用類型蹂匹,則遞歸地加載。
加載階段和連接階段的部分內(nèi)容(比如一部分字節(jié)碼文件格式的驗(yàn)證動(dòng)作)時(shí)交叉進(jìn)行的凹蜈,但兩者的開(kāi)始時(shí)間肯定是保持先后順序的限寞。

驗(yàn)證

驗(yàn)證步驟是為了確保Class文件的字節(jié)流中的信息符合JVM要求,且不危害JVM安全仰坦。驗(yàn)證過(guò)程又細(xì)分為以下4個(gè)子過(guò)程:

  1. 文件格式驗(yàn)證:驗(yàn)證是否符合Class文件格式履植,如果驗(yàn)證到不符合Class文件格式約束,則JVM拋出java.lang.VerifyError異城幕危或其子類玫霎;
  2. 元數(shù)據(jù)驗(yàn)證:進(jìn)行語(yǔ)義分析,保證其符合Java語(yǔ)言規(guī)范传泊;
  3. 字節(jié)碼驗(yàn)證:通過(guò)數(shù)據(jù)流和控制流分析鼠渺,確認(rèn)語(yǔ)義合法且符合邏輯。JDK1.6之后的javac在Code屬性的屬性表里面增加了一項(xiàng)“StackMapTable”屬性眷细,描述了方法提中所有基本塊(按控制流拆分的代碼塊)開(kāi)始時(shí)本地變量表和操作棧應(yīng)有的狀態(tài)拦盹,字節(jié)碼驗(yàn)證過(guò)程中秩序檢查StackMapTable屬性的記錄是否合法即可;
  4. 符號(hào)引用驗(yàn)證:在連接的第三階段——解析階段中溪椎,JVM將符號(hào)引用轉(zhuǎn)化為直接引用進(jìn)行符號(hào)引用驗(yàn)證普舆,對(duì)類自身以外的信息進(jìn)行匹配行校驗(yàn),比如符號(hào)引用的類是否能找到校读,類沼侣、方法、字段的訪問(wèn)性是否能被當(dāng)前類訪問(wèn)歉秫。

準(zhǔn)備

為類的靜態(tài)變量分配內(nèi)存蛾洛,并初始化其值(初始化為零值)。如果有定義其取值雁芙,且非final變量轧膘,比如

public static String test = "test";

test變量不是final變量,會(huì)被初始化為零值null兔甘,在初始化階段調(diào)用<clinit>方法時(shí)才會(huì)賦值”test”谎碍。
而一個(gè)final的靜態(tài)變量,即常量洞焙,如:

public final static String test = "test";

是會(huì)通過(guò)ConstantValue屬性在準(zhǔn)備階段就初始化為”test”蟆淀。

解析

JVM將常量池的符號(hào)引用替換為直接引用的過(guò)程拯啦。JVM規(guī)范要求在調(diào)用符號(hào)引用操作的字節(jié)碼指令之前必須先對(duì)其所使用的符號(hào)引用進(jìn)行解析。JVM會(huì)將第一次解析結(jié)果進(jìn)行緩存熔任,避免解析動(dòng)作重復(fù)進(jìn)行褒链。

初始化

初始化是類加載過(guò)程的最后一步,執(zhí)行類構(gòu)造器<clinit>()方法笋敞。

類加載器

類加載器就是通過(guò)一個(gè)類的全限定名來(lái)獲取描述此類的二進(jìn)制字節(jié)流這個(gè)動(dòng)作的模塊碱蒙。類加載器在類層次劃分荠瘪、OSGi夯巷、熱部署、代碼加密等領(lǐng)域大放異彩哀墓。

1趁餐、類與類加載器

比較兩個(gè)類是否“相等”,只有在這兩個(gè)類是由同一個(gè)類加載器加載的前提之下才有意義篮绰,包括類的Class對(duì)象的equals方法后雷、isAssignableFrom()方法、isInstance()方法吠各。

2臀突、雙親委派模型

類加載器劃分:

  • 啟動(dòng)器加載器(Bootstrap ClassLoader):這個(gè)類加載器使用C++語(yǔ)言實(shí)現(xiàn)負(fù)責(zé)將< JAVA_HOME >/lib目錄中的或者被-Xbootclasspath參數(shù)指定的路徑中的,并且是虛擬機(jī)識(shí)別的類庫(kù)加載到虛擬機(jī)內(nèi)存中贾漏。啟動(dòng)類加載器無(wú)法被Java程序直接引用候学。
  • 擴(kuò)展類加載器(Extension ClassLoader):這個(gè)加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),負(fù)責(zé)加載< JAVA_HOME >\lib\ext目錄中的纵散,或被java.ext.dirs系統(tǒng)變量指定路徑中的所有類庫(kù)梳码,開(kāi)發(fā)者可用直接使用擴(kuò)展類加載器。
  • 應(yīng)用程序類加載器(Application ClassLoader):由sun.misc.Launcher$AppClassLoader來(lái)實(shí)現(xiàn)伍掀,這個(gè)類加載器是ClassLoader中的getSystemClassLoader()方法的返回值掰茶,所以稱它為系統(tǒng)類加載器,如果應(yīng)用程序沒(méi)有定義過(guò)自己的類加載器蜜笤,一般情況下這個(gè)就是程序中默認(rèn)的類加載器濒蒋。
image

雙親委派模型要求除了頂層的啟動(dòng)類加載器外,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器把兔。其工作過(guò)程是:如果一個(gè)類加載器收到了類加載的請(qǐng)求沪伙,它首先把請(qǐng)求委派給父類加載器去完成,每一個(gè)層次的類加載器都是如此垛贤;只有當(dāng)父加載器反饋?zhàn)约簾o(wú)法完成這個(gè)加載請(qǐng)求時(shí)焰坪,子加載器才會(huì)嘗試自己去加載。

好處:Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系聘惦。例如java.lang.Object某饰,它存放在rt.jar中儒恋,無(wú)論哪一個(gè)類加載器要加載這個(gè)類,最終都是委派給啟動(dòng)類加載器進(jìn)行加載黔漂。

3诫尽、破壞雙親委派模型

雙親委派模型主要出現(xiàn)過(guò)三次較大規(guī)模的“被破壞”情況。

  • 第一次:JDK1.2引入雙親委派模型時(shí)做出妥協(xié)炬守,向前兼容
  • 第二次:JNDI服務(wù)牧嫉,它的代碼有啟動(dòng)類加載器去加載,但JNDI需要調(diào)用ClassPath下的代碼减途,啟動(dòng)類加載器可能不認(rèn)識(shí)酣藻。解決:加入線程上下文類加載器,JNDI使用這個(gè)線程上下文類加載器加載所需要的SPI代碼鳍置。
  • 第三次:程序動(dòng)態(tài)性辽剧。OSGi實(shí)現(xiàn)模塊化熱部署,每一個(gè)程序模塊都有一個(gè)自己的類加載器税产,當(dāng)需要更換一個(gè)Bundle時(shí)怕轿,就把這個(gè)Bundle連同類加載器一起換掉以實(shí)現(xiàn)代碼熱替換。

<clinit>方法由編譯器自動(dòng)收集類中所有靜態(tài)變量的賦值動(dòng)作以及靜態(tài)代碼塊合并生成的辟拷,按源文件中出現(xiàn)的順序(即靜態(tài)代碼塊對(duì)于其后的靜態(tài)變量撞羽,可以賦值,但不能訪問(wèn))衫冻。<clinit>方法不需要調(diào)用父類的類構(gòu)造器诀紊,JVM會(huì)保證<clinit>執(zhí)行前父類的<clinit>方法已經(jīng)執(zhí)行,所以JVM第一個(gè)執(zhí)行的<clinit>方法是Object的羽杰。JVM會(huì)保證多線程環(huán)境中<clinit>方法執(zhí)行的安全性渡紫,保證只有一個(gè)線程去執(zhí)行。
<clinit>方法不是必須的考赛,比如沒(méi)有靜態(tài)變量的接口惕澎,或沒(méi)有靜態(tài)代碼塊和靜態(tài)變量的類。

編譯期優(yōu)化

javac對(duì)代碼的運(yùn)行效率幾乎沒(méi)有任何優(yōu)化措施(JDK1.3之后-O優(yōu)化參數(shù)沒(méi)有意義了)颜骤,性能優(yōu)化主要集中在運(yùn)行期(后端的即時(shí)編譯期)唧喉,javac主要進(jìn)行了一些針對(duì)Java語(yǔ)言編碼過(guò)程的優(yōu)化,如語(yǔ)法糖忍抽。

編譯過(guò)程

編譯過(guò)程大概分為3個(gè)過(guò)程:


image

javac中的代碼是這樣的:


image
  1. 解析與填充符號(hào)表過(guò)程:首先進(jìn)行詞法八孝、語(yǔ)法分析,將源代碼的字符流轉(zhuǎn)換為Token集合鸠项,然后根據(jù)Token序列構(gòu)造抽象語(yǔ)法樹(shù)AST干跛,對(duì)應(yīng)parseFiles()方法;然后填充符號(hào)表(記錄符號(hào)地址和符號(hào)信息映射關(guān)系)祟绊,符號(hào)表中記錄的信息在編譯的不同階段都會(huì)用到楼入,對(duì)應(yīng)enterTress()方法哥捕;
  2. 插入式注解處理器的注解處理過(guò)程:處理代碼中的注解,這個(gè)過(guò)程中可能影響到語(yǔ)法樹(shù)的元素嘉熊,如果影響到了遥赚,則要重新回到解析及填充符號(hào)表的過(guò)程,這樣一個(gè)循環(huán)稱作一個(gè)Round阐肤,直到注解處理器沒(méi)有對(duì)語(yǔ)法樹(shù)進(jìn)行修改凫佛;
  3. 分析與字節(jié)碼生成過(guò)程:具體又分為標(biāo)注檢查(檢查變量使用前是否已生命、變量與賦值之間類型是否匹配等問(wèn)題孕惜,以及常量折疊愧薛,如”1”+”2”優(yōu)化為”12”)、數(shù)據(jù)及控制流分析(檢查局部變量使用前是否賦值诊赊、每條路徑是否都有返回值厚满、異常是否都處理了等問(wèn)題)、解語(yǔ)法糖(由desugar()方法完成)碧磅、字節(jié)碼生成(收斂生成<clinit>()方法he <init>()方法,將所有生成的信息轉(zhuǎn)換成字節(jié)碼寫入磁盤)等子過(guò)程遵馆。

語(yǔ)法糖

泛型

Java的泛型是偽泛型鲸郊,只在源碼中存在,編譯時(shí)進(jìn)行類型擦除變成原生類型(Raw Type)货邓,并在調(diào)用的地方加上強(qiáng)轉(zhuǎn)類型代碼秆撮,這是為了兼容舊版本。對(duì)于重載方法换况,如果泛型參數(shù)的泛型類型不同而其他參數(shù)以及返回類型相同职辨,是不允許重載的,比如以下方法1和方法2不能重載戈二;而如果泛型參數(shù)的泛型類型不同舒裤,且返回類型不同,則可以重載觉吭,比如方法1和方法3(JVM本來(lái)就允許)腾供。

//方法1和方法2不能重載,方法1和方法3可以重載
//方法1
public String test(List<Integer>);
//方法2
public String test(List<String>);
//方法3
public int test(List<String>);

自動(dòng)裝箱/拆箱鲜滩、遍歷循環(huán)伴鳖、變長(zhǎng)參數(shù)

遍歷循環(huán)(增強(qiáng)for)的實(shí)現(xiàn)是編譯時(shí)還原為迭代其的實(shí)現(xiàn),因此需要實(shí)現(xiàn)Iterable接口徙硅。

條件編譯

java的條件編譯通過(guò)條件為常量的if語(yǔ)句實(shí)現(xiàn)榜聂。如下面代碼中,編譯后的字節(jié)碼不會(huì)包含調(diào)用B()方法的指令嗓蘑。

if(true){
    A();
} else {
    B();
}

運(yùn)行期優(yōu)化

解釋器與編譯器

許多主流商用JVM包括HotSpot采用解釋器與編譯器并存的結(jié)構(gòu)须肆,啟動(dòng)的時(shí)候使用解釋器贴汪,保證啟動(dòng)速度,隨著運(yùn)行時(shí)間推移休吠,編譯器發(fā)揮作用扳埂,編譯為本地代碼,提高執(zhí)行效率瘤礁。在JVM中這種模式被稱為混合模式阳懂,可以用-Xint強(qiáng)制JVM運(yùn)行于解釋模式,或用-Xcomp強(qiáng)制JVM運(yùn)行于編譯模式柜思。HotSpot包含兩個(gè)及時(shí)編譯器Client Compiler和Server Compiler岩调,一般簡(jiǎn)稱為C1和C2。

熱點(diǎn)探測(cè)

運(yùn)行過(guò)程中被即時(shí)編譯器編譯的熱點(diǎn)代碼包括被多次調(diào)用的方法或#循環(huán)體赡盘,對(duì)于后者編譯器還是會(huì)以整個(gè)方法作為編譯對(duì)象号枕。
判斷方法或循環(huán)體是否熱點(diǎn)代碼的行為被稱為熱點(diǎn)探測(cè),目前主要的熱點(diǎn)探測(cè)方法有兩種:

  1. 基于采樣的熱點(diǎn)探測(cè)陨享。JVM周期性的檢查各個(gè)線程的棧頂葱淳,如果發(fā)現(xiàn)某些方法經(jīng)常出現(xiàn)在棧頂,那么就是熱點(diǎn)方法抛姑。缺點(diǎn)是容易收到線程阻塞或其他外界因素影響赞厕,優(yōu)點(diǎn)是簡(jiǎn)單高效;
  2. 基于計(jì)數(shù)器的熱點(diǎn)探測(cè)定硝。為每個(gè)方法甚至代碼塊建立計(jì)數(shù)器皿桑,統(tǒng)計(jì)執(zhí)行次數(shù),超過(guò)一定閾值就認(rèn)為是熱點(diǎn)方法蔬啡。缺點(diǎn)是不能獲取導(dǎo)方法的調(diào)用關(guān)系诲侮,優(yōu)點(diǎn)是精確且嚴(yán)謹(jǐn)。

HotSpot使用第二種箱蟆,準(zhǔn)備了方法調(diào)用計(jì)數(shù)器回邊計(jì)數(shù)器沟绪。前者統(tǒng)計(jì)方法被調(diào)用的次數(shù),默認(rèn)的閾值:Client模式1500次顽腾,Server模式10000次近零,可以通過(guò)-XX:CompileThreshold來(lái)設(shè)定;后者統(tǒng)計(jì)循環(huán)體被執(zhí)行的次數(shù)抄肖,字節(jié)碼遇到控制流向后跳轉(zhuǎn)的指令稱為回邊(Back Edge)久信,通過(guò)-XX:BackEdgeThreshold來(lái)手動(dòng)設(shè)置閾值。
對(duì)于方法調(diào)用計(jì)數(shù)器漓摩,一個(gè)方法執(zhí)行時(shí)先判斷存不存在JIT編譯過(guò)的版本裙士,存在的話執(zhí)行編譯后版本,不存在的話計(jì)數(shù)器加一管毙,再判斷是否超過(guò)閾值腿椎,超過(guò)的話向即時(shí)編譯器提交編譯申請(qǐng)桌硫。其統(tǒng)計(jì)的并不是方法被調(diào)用的絕對(duì)次數(shù),而是一段時(shí)間內(nèi)的調(diào)用次數(shù)啃炸,如果超過(guò)一定時(shí)間計(jì)數(shù)器仍不足閾值铆隘,則計(jì)數(shù)值會(huì)減少一半,這被成為熱度衰減(Counter Decay)南用,這段時(shí)間被稱為半衰期膀钠。熱度衰減的動(dòng)作時(shí)在GC時(shí)順便進(jìn)行的。
回邊計(jì)數(shù)器沒(méi)有計(jì)數(shù)熱度衰減的過(guò)程裹虫,記錄循環(huán)體被調(diào)用的絕對(duì)次數(shù)肿嘲。
默認(rèn)配置下,編譯是在后臺(tái)的編譯線程進(jìn)行的筑公,除非用-XX:-BackgroundCompilation來(lái)禁止后臺(tái)編譯雳窟,這樣提交編譯請(qǐng)求的線程會(huì)一直等待編譯完成。

編譯優(yōu)化技術(shù)

JVM幾乎所有的優(yōu)化措施都集中在及時(shí)編譯器中匣屡。

方法內(nèi)聯(lián)

方法內(nèi)聯(lián)(Method Inlining)指的是將調(diào)用的方法代碼替換掉調(diào)用者的調(diào)用語(yǔ)句封救。目的:

  1. 取出調(diào)用方法的成本,如建立棧幀耸采;
  2. 為其他優(yōu)化建立良好基礎(chǔ)兴泥,比如內(nèi)聯(lián)可以發(fā)現(xiàn)更多的無(wú)用代碼。

考慮到多態(tài)虾宇,方法內(nèi)聯(lián)的實(shí)現(xiàn)并不簡(jiǎn)單,在編譯器無(wú)法得出調(diào)用的方法是哪個(gè)版本的結(jié)論(父類還是子類)如绸,需要在運(yùn)行期確定嘱朽。
JVM引入了類型繼承關(guān)系分析(Class Hierarchy Analysis,CHA)技術(shù)怔接,用于確定目前加載的類中某個(gè)接口是否有多于一種的實(shí)現(xiàn)搪泳、某類是否存在子類、子類是否抽象等信息扼脐。進(jìn)行內(nèi)聯(lián)時(shí):

  1. 如果目標(biāo)方法是非虛方法(私有方法岸军、實(shí)力構(gòu)造器、父類方法瓦侮、靜態(tài)方法等)艰赞,那么直接進(jìn)行內(nèi)聯(lián);
  2. 對(duì)于虛方法肚吏,向CHA查詢?cè)摲椒ㄊ欠裼卸鄠€(gè)版本可選方妖,如果只有一個(gè)版本,則直接進(jìn)行內(nèi)聯(lián)罚攀,此時(shí)屬于激進(jìn)優(yōu)化党觅,需要預(yù)留逃生門(守護(hù)內(nèi)聯(lián))雌澄,此后如果JVM沒(méi)有加載到改變方法接受者的繼承關(guān)系的類,則可以繼續(xù)使用內(nèi)聯(lián)優(yōu)化的版本杯瞻,否則拋棄已編譯的代碼镐牺、退回到解釋狀態(tài)進(jìn)行或重新編譯;
  3. 如果虛方法有多個(gè)版本魁莉,則嘗試內(nèi)聯(lián)緩存(Inline Cache)睬涧。發(fā)生方法調(diào)用前,內(nèi)聯(lián)緩存狀態(tài)為空沛厨;第一次調(diào)用后宙地,緩存記錄下方法接受者的版本信息,每次進(jìn)行方法調(diào)用的時(shí)候都比較接受者版本逆皮,如果方法接受者版本一樣宅粥,則繼續(xù)調(diào)用內(nèi)聯(lián)緩存進(jìn)行內(nèi)聯(lián),否則取消內(nèi)聯(lián)电谣。

冗余訪問(wèn)消除

冗余訪問(wèn)消除(Redundant Loads Elimination)指的是如果能保證一個(gè)方法的兩次調(diào)用之間的代碼不會(huì)引起其返回值的更改秽梅,那么這第二次調(diào)用的結(jié)果可以直接用第一次調(diào)用結(jié)果去賦值,比如一下代碼:

public void foo1(){
    y=b.value;
    //其他調(diào)用剿牺,不會(huì)影響b.value的返回值
    z=b.value();
}

以上代碼可以優(yōu)化為:

public void foo1(){
    y=b.value;
    //其他調(diào)用企垦,不會(huì)影響b.value的返回值
    z=y;
}

復(fù)寫傳播

復(fù)寫傳播(Copy Propagation)指的是去掉重復(fù)的變量。

無(wú)用代碼消除

無(wú)用代碼消除(Dead Code Elimination)晒来,無(wú)用代碼指的是永遠(yuǎn)不會(huì)izhixing的代碼钞诡,或者完全沒(méi)有意義的代碼。

公共子表達(dá)式消除

Common Subexpression Elimination定義:一個(gè)表達(dá)式E已經(jīng)計(jì)算過(guò)湃崩,且計(jì)算后到現(xiàn)在E的變量全部沒(méi)有變化荧降,那么E這次出現(xiàn)成為了公共子表達(dá)式,無(wú)需重復(fù)計(jì)算攒读,直接用前面計(jì)算結(jié)果替換即可朵诫。如果消除優(yōu)化僅限于程序基本塊內(nèi),則成為局部公共子表達(dá)式消除薄扁,如果覆蓋范圍涵蓋多個(gè)基本塊剪返,則成為全局公共子表達(dá)式消除。

數(shù)組邊界檢查消除

Java訪問(wèn)數(shù)組元素時(shí)邓梅,會(huì)對(duì)下標(biāo)進(jìn)行上下界范圍檢查脱盲,不滿足上下界時(shí)會(huì)拋出ArrayIndexOutOfBoundsException異常。
編譯器根據(jù)數(shù)據(jù)流分析確定數(shù)組長(zhǎng)度震放,并判斷小表有無(wú)月結(jié)宾毒;在循環(huán)中進(jìn)行數(shù)組訪問(wèn)時(shí),也是可以通過(guò)數(shù)據(jù)流分析判定循環(huán)變量的取值是否越界,如果能保證循環(huán)體中不越界的話循環(huán)體中訪問(wèn)數(shù)組的語(yǔ)句可以消除邊界檢查诈铛。
還有一種思路時(shí)隱式異常處理乙各,將空指針檢查和除數(shù)為零檢查消除,注冊(cè)一個(gè)Segment Fault信號(hào)的異常處理器幢竹,放在異常處理里面耳峦,在這個(gè)異常處理器里面再轉(zhuǎn)換為對(duì)應(yīng)的異常并拋出。
還有一些其他的消除操作焕毫,比如自動(dòng)裝箱消除蹲坷、安全點(diǎn)消除、消除反射等等邑飒。

逃逸分析

逃逸分析不能直接優(yōu)化代碼循签,而是為其他優(yōu)化手段提供優(yōu)化的依據(jù)。逃逸分析指的是分析對(duì)象動(dòng)態(tài)作用域:一個(gè)對(duì)象在方法中被定義后疙咸,被外部方法引用县匠,則稱為方法逃逸,被外部線程引用訪問(wèn)到的話撒轮,被稱為線程逃逸乞旦。如果能證明一個(gè)對(duì)象不會(huì)逃逸到方法或線程外,則可以進(jìn)行以下優(yōu)化:

  1. 棧上分配(Stack Allocation):若確認(rèn)對(duì)象沒(méi)有方法逃逸题山,可以將其在棧上分配內(nèi)存兰粉,則其占用內(nèi)存會(huì)隨著棧幀出棧而被銷毀,減少GC壓力顶瞳,而一般應(yīng)用中不逃逸的局部對(duì)象占很大比例玖姑;
  2. 同步消除(Synchronization Elimination):若確認(rèn)對(duì)象沒(méi)有線程逃逸,可以對(duì)該變量實(shí)時(shí)的同步措施消除慨菱;
  3. 標(biāo)量替換(Scalar Replacement):標(biāo)量指一個(gè)數(shù)據(jù)無(wú)法再分解為更小的數(shù)據(jù)來(lái)表示客峭,如基礎(chǔ)數(shù)據(jù)類型,反之稱之為聚合量(Aggregate)抡柿,如對(duì)象。若確認(rèn)一個(gè)對(duì)象沒(méi)有逃逸等恐,則可以不創(chuàng)建對(duì)象洲劣,改為直接創(chuàng)建它會(huì)被使用到的成員變量來(lái)代替,同時(shí)可以保存在棧上课蔬,提高讀寫效率囱稽,并為進(jìn)一步優(yōu)化創(chuàng)造條件。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末二跋,一起剝皮案震驚了整個(gè)濱河市战惊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扎即,老刑警劉巖吞获,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件况凉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡各拷,警方通過(guò)查閱死者的電腦和手機(jī)刁绒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)烤黍,“玉大人知市,你說(shuō)我怎么就攤上這事渠抹∈唬” “怎么了掠手?”我有些...
    開(kāi)封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵溶浴,是天一觀的道長(zhǎng)荆几。 經(jīng)常有香客問(wèn)我撩笆,道長(zhǎng)唧取,這世上最難降的妖魔是什么航夺? 我笑而不...
    開(kāi)封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任媳叨,我火速辦了婚禮腥光,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘糊秆。我一直安慰自己武福,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布痘番。 她就那樣靜靜地躺著捉片,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汞舱。 梳的紋絲不亂的頭發(fā)上伍纫,一...
    開(kāi)封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音昂芜,去河邊找鬼莹规。 笑死,一個(gè)胖子當(dāng)著我的面吹牛泌神,可吹牛的內(nèi)容都是我干的良漱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼欢际,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼母市!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起损趋,我...
    開(kāi)封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤患久,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蒋失,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡返帕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了高镐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溉旋。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嫉髓,靈堂內(nèi)的尸體忽然破棺而出观腊,到底是詐尸還是另有隱情,我是刑警寧澤算行,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布梧油,位于F島的核電站,受9級(jí)特大地震影響州邢,放射性物質(zhì)發(fā)生泄漏儡陨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一量淌、第九天 我趴在偏房一處隱蔽的房頂上張望骗村。 院中可真熱鬧,春花似錦呀枢、人聲如沸胚股。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)琅拌。三九已至,卻和暖如春摘刑,著一層夾襖步出監(jiān)牢的瞬間进宝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工枷恕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留党晋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓徐块,卻偏偏與公主長(zhǎng)得像隶校,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蛹锰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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