內(nèi)存分配以及回收
Java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū),分為以下幾個(gè)模塊,包含所有線程共有的數(shù)據(jù)區(qū)和線程單獨(dú)享有的數(shù)據(jù)區(qū)。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名與空間、網(wǎng)絡(luò)空間、營(yíng)銷軟件、網(wǎng)站建設(shè)、江北網(wǎng)站維護(hù)、網(wǎng)站推廣。
- 程序計(jì)數(shù)器:字節(jié)碼行號(hào),通過(guò)這個(gè)計(jì)數(shù)器來(lái)選取下一條需要執(zhí)行的指令,線程獨(dú)有。
- 虛擬機(jī)棧:線程私有。方法在執(zhí)行時(shí)會(huì)創(chuàng)建一個(gè)棧幀,用于存儲(chǔ)局部變量表等。局部變量表中存放了編譯器可知的基本數(shù)據(jù)類型、對(duì)象引用、returnAddress(指向了一條字節(jié)碼指令的地址)
- 本地方法棧:與虛擬機(jī)棧類似,只不過(guò)這個(gè)地方是為native方法服務(wù)。
- 堆:線程共用。存放對(duì)象實(shí)例。
- 方法區(qū):線程共用。存儲(chǔ)已經(jīng)被虛擬機(jī)加載的類信息、常量、靜態(tài)變量等。
- 運(yùn)行時(shí)常量池:用于存放編譯期生成的字面量和符合引用。字面量就是我們所說(shuō)的常量概念,如文本字符串、被聲明為final的常量值等。符號(hào)引用是一組符號(hào)來(lái)描述所引用的目標(biāo),符號(hào)可以是任何形式的字面量,只要使用時(shí)能無(wú)歧義地定位到目標(biāo)即可,一般包括下面三類常量:類和接口的全限定名、字段的名稱和描述符、方法的名稱和描述符。

JVM通過(guò)根搜索算法來(lái)判定對(duì)象是否可以回收,一般對(duì)于不能從根(GC Roots)搜索到的對(duì)象是可以被回收的。
能夠被作為GC Roots對(duì)象有:虛擬機(jī)棧本地變量表中引用的對(duì)象(也就是正在調(diào)用的方法中引用的);方法區(qū)中靜態(tài)屬性或常量引用的對(duì)象;本地方法棧引用的對(duì)象。
可以被回收的對(duì)象并不一定絕對(duì)被回收,JVM先做一次標(biāo)記和篩選,把那些覆蓋了finalize方法的對(duì)象篩選出來(lái)然后觸發(fā)finalize方法,如果在finalize方法中對(duì)象復(fù)活,則不回收,否則回收,且finalize方法僅會(huì)被觸發(fā)一次。
垃圾回收算法
- 標(biāo)記-清除:把標(biāo)記為待回收的對(duì)象空間清除,容易造成大量空間碎片;
- 復(fù)制算法:將內(nèi)存分為三個(gè)區(qū)域,一個(gè)較大的eden區(qū)和兩個(gè)較小的survivor區(qū)。每次GC都把存活的對(duì)象挪到其中一個(gè)servivor區(qū),然后把eden全部清除。只對(duì)每次GC時(shí)存活對(duì)象較少時(shí)比較有效,適用于新生代;
- 標(biāo)記-整理:把標(biāo)記后存活的對(duì)象向一個(gè)方向移動(dòng),然后清除其它空間。比較適合老年代。
內(nèi)存分配與回收策略
- 對(duì)象默認(rèn)優(yōu)先分配在新生代;
- 大對(duì)象直接分配到老年代;
- 長(zhǎng)期存活的對(duì)象轉(zhuǎn)移到老年代:虛擬機(jī)給每個(gè)對(duì)象定義一個(gè)對(duì)象年齡,沒(méi)發(fā)生一次minor GC,年齡就增加一次,超過(guò)默認(rèn)值之后就會(huì)進(jìn)入到老年代。
- 動(dòng)態(tài)對(duì)象年齡判定:對(duì)象不一定是必須到了默認(rèn)年齡才能進(jìn)入老年代,如果一個(gè)eden區(qū)中所有相同年齡的對(duì)象大小綜合超過(guò)eden一半的空間,那么大于等于這個(gè)年齡的對(duì)象也會(huì)進(jìn)入老年代。
類文件結(jié)構(gòu)
class文件是二進(jìn)制組成的,class有兩種數(shù)據(jù)類型:無(wú)符號(hào)數(shù)和表。
無(wú)符號(hào)數(shù)是基礎(chǔ)數(shù)據(jù)類型,其中u1表示1個(gè)字節(jié)、u2表示2個(gè)字節(jié)(一個(gè)字節(jié)8個(gè)bit,而4個(gè)bit可以表示1個(gè)16進(jìn)制的數(shù),也就是說(shuō)1個(gè)字節(jié)可以用2個(gè)16進(jìn)制數(shù)表示);
表是由多個(gè)無(wú)符號(hào)數(shù)或其它表構(gòu)成的。

- magic是4個(gè)字節(jié),也就是8個(gè)16進(jìn)制數(shù),固定為CAFEBABE;后面分別是兩個(gè)版本號(hào)。
- 常量池:跟著版本號(hào)之后的就是常量池(字面量和符號(hào)引用)。由于無(wú)法確認(rèn)一個(gè)類中常量池有多少常量,所有先有一個(gè)值來(lái)標(biāo)志有多少個(gè),然后再是常量具體信息。
- 訪問(wèn)標(biāo)志:常量池之后跟著的是2個(gè)字節(jié)的訪問(wèn)標(biāo)志。需要被標(biāo)志的內(nèi)容包括:是否public、是否final、是否abstract、是類或接口
- 訪問(wèn)標(biāo)志之后是類索引(用于確定該類的全限定名)、父類索引(用于確定父類的全限定名)、接口所有集合(實(shí)現(xiàn)的接口可能不止一個(gè))
- 字段表集合:描述接口或類中聲明的變量,包含類變量和實(shí)例變量。
- 方法表集合:描述類或接口中聲明的fangfa。
- 屬性表結(jié)合:
code屬性:java方法體中的代碼經(jīng)javac編譯后會(huì)存儲(chǔ)在code屬性中(接口中方法或抽象方法沒(méi)有code屬性)
Exceptions屬性:列舉出方法throws后面拋出的異常;
其它各屬性不再一一列舉。
類加載機(jī)制

類加載的時(shí)機(jī)
主動(dòng)引用的幾種情況才會(huì)加載(前提是此類沒(méi)有被加載過(guò))
- new一個(gè)對(duì)象、引用類的static變量(final變量除外)、調(diào)用類的static方法;
- 對(duì)類進(jìn)行反射調(diào)用時(shí);
- 初始化一個(gè)類時(shí),如果父類沒(méi)有被初始化,則先初始化父類;
- 虛擬機(jī)啟動(dòng)時(shí),初始化包含main方法的那個(gè)類
被動(dòng)引用不會(huì)觸發(fā)初始化
- 調(diào)用父類靜態(tài)方法,不會(huì)初始化子類;
- 通過(guò)數(shù)組定義引用類,不會(huì)觸發(fā)初始化;
- 引用靜態(tài)常量不會(huì)觸發(fā)。
加載過(guò)程
- 通過(guò)一個(gè)類全限定名獲取定義此類的二進(jìn)制字節(jié)流(一般是class文件)
- 將二進(jìn)制字節(jié)流轉(zhuǎn)化為方法區(qū)中的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
- 在內(nèi)存(堆)中生成這個(gè)類的Class類的對(duì)象,作為方法區(qū)這個(gè)類的各個(gè)數(shù)據(jù)的訪問(wèn)入口
連接過(guò)程
- 驗(yàn)證階段:文件格式驗(yàn)證(是否符合Class文件規(guī)范)、元數(shù)據(jù)驗(yàn)證(是否符合java語(yǔ)法規(guī)范)、字節(jié)碼驗(yàn)證(確保語(yǔ)義是符合邏輯的)、符合引用驗(yàn)證。
- 準(zhǔn)備階段:正式為類變量分配內(nèi)存并設(shè)置初始值。
有兩點(diǎn)需要注意:
一,此處只為類變量分配內(nèi)存(static修飾的),不包含實(shí)例變量;
二,設(shè)置的初始值是這個(gè)類型的0值,不是實(shí)際值(但被final修飾的賦的就是實(shí)際值) - 解析階段:將符合引用替換為直接引用
初始化過(guò)程
初始化過(guò)程主要是執(zhí)行類構(gòu)造器<cinit>方法
- <cinit>方法主要是手機(jī)所有類變量的賦值動(dòng)作,和靜態(tài)語(yǔ)句塊(staic {});
- 虛擬機(jī)會(huì)保證<cinit>方法在父類中先調(diào)用,這樣說(shuō)明父類的static語(yǔ)句塊要比子類的static變量賦值操作先執(zhí)行,以下代碼中,字段B的值將會(huì)是2

- 這也說(shuō)明了一個(gè)問(wèn)題:new一個(gè)對(duì)象時(shí),靜態(tài)變量賦值和靜態(tài)語(yǔ)句塊會(huì)在類的構(gòu)造方法前執(zhí)行。
類加載器
- 比較兩個(gè)類對(duì)象是否相等,只有加載兩個(gè)類加載器的完全一樣,才有意義;
- 如果一個(gè)類加載器收到一個(gè)類加載請(qǐng)求,它首先會(huì)請(qǐng)求委派給父類加載器完成,父類無(wú)法完成時(shí),子類加載器才進(jìn)行加載。
虛擬機(jī)字節(jié)碼執(zhí)行引擎

運(yùn)行時(shí)棧幀結(jié)構(gòu)
- 局部變量表:存放方法參數(shù)和局部變量。每個(gè)變量以slot為單位,slot可以復(fù)用
注意,如果沒(méi)有int a = 0這一行代碼,placeholder是不會(huì)被回收的,因?yàn)槿绻患舆@行代碼,就沒(méi)有任何對(duì)局部變量表的讀寫操作,這個(gè)slot就不會(huì)被占用。 - 操作數(shù)棧:方法執(zhí)行過(guò)程中,會(huì)有各種字節(jié)碼出棧入棧
- 動(dòng)態(tài)鏈接:一部分符合引用在類加載時(shí)轉(zhuǎn)化為直接引用,這是靜態(tài)機(jī)械;而一部分則是運(yùn)行時(shí)轉(zhuǎn)化為直接應(yīng)用,這叫動(dòng)態(tài)鏈接
方法調(diào)用和分派
- 所有的方法在Class文件中都是一個(gè)符合引用,而一部分方法在類加載時(shí)就直接解析為直接引用。這種方法必須是“編譯時(shí)已知,運(yùn)行時(shí)不可變”,就是靜態(tài)方法和私有方法兩大類
- 靜態(tài)分派:依賴靜態(tài)類型來(lái)定位方法執(zhí)行版本稱為靜態(tài)分派,典型應(yīng)用是重載。

Human是靜態(tài)類型,后面的Man和Women則是實(shí)際類型。
靜態(tài)類型在編譯器可知,而動(dòng)態(tài)類型則是在運(yùn)行時(shí)才能知道。 - 動(dòng)態(tài)分派:運(yùn)行期間根據(jù)實(shí)際類型來(lái)確定方法執(zhí)行版本,典型應(yīng)用是覆蓋。

結(jié)果是

內(nèi)存模型及線程安全

JMM規(guī)定所有內(nèi)存都存儲(chǔ)于主內(nèi)存中,每條線程還有自己的工作內(nèi)存。
變量的讀取、賦值操作必須在工作內(nèi)存中進(jìn)行。
內(nèi)存直接的交互操作,主要有以下8種操作:


8種操作需要滿足以下規(guī)則

volatile關(guān)鍵字
- volatile關(guān)鍵字保證了變量的所有線程的可見(jiàn)性,但并非是線程安全的。
兩種情況下是線程不安全的:
一,變量依賴于自身(比如i++之類的)
二,變量依賴于其它變量(比如i=a+3) - volatile禁止語(yǔ)義重排序
- volatile的具體實(shí)現(xiàn)

當(dāng)前題目:Java虛擬機(jī)
本文來(lái)源:http://www.yijiale78.com/article20/pcsejo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、商城網(wǎng)站、標(biāo)簽優(yōu)化、網(wǎng)站營(yíng)銷、品牌網(wǎng)站制作、動(dòng)態(tài)網(wǎng)站
廣告
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源:
創(chuàng)新互聯(lián)