成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java虛擬機學(xué)習(xí)

RobinTang / 3499人閱讀

摘要:虛擬機學(xué)習(xí)是一個虛構(gòu)出來的計算機有自己的處理器堆棧寄存器以及相應(yīng)的指令系統(tǒng)等。類裝載器子系統(tǒng)涉及虛擬機的其它組成部分和來自庫的類。運行中的程序的每一個線程都是一個獨立的虛擬機執(zhí)行引擎的實例。

Java虛擬機學(xué)習(xí) JVM

JVM是一個虛構(gòu)出來的計算機,有自己的處理器,堆棧,寄存器以及相應(yīng)的指令系統(tǒng)等。JVM是JRE的一部分,通過在實際的計算機上仿真模擬各種計算機功能,這樣就能使Java在跨平臺上運行。

JVM內(nèi)存區(qū)域劃分

JVM的內(nèi)部體系結(jié)構(gòu)分為三個部分,分別為類裝載器子系統(tǒng),運行時數(shù)據(jù)區(qū)和執(zhí)行引擎。

類裝載器子系統(tǒng)(ClassLoader)

每個Java虛擬機都有一個類加載器,負責(zé)查找并加載程序中的類,接口,并給其確定唯一的名字。Java虛擬機有兩種類裝載器:系統(tǒng)類裝載器和用戶自定義類裝載器,系統(tǒng)類裝載器是JVM實現(xiàn)的一部分,用戶自定義類裝載器是Java程序的一部分,其必須是類裝載器ClassLoader類的子類。

啟動類裝載器(bootstrap calss loader): 其用來加載Java的核心庫,用原生代碼來實現(xiàn)的,沒有繼承java.lang.ClassLoader

擴展類裝載器(extensions class loader): 其用來加載Java的擴展庫,Jav虛擬機的實現(xiàn)會提供一個擴展庫目錄,該裝載器就是在這個目錄下查找加載類。

應(yīng)用程序類裝載器(application class loader): 其根據(jù)java應(yīng)用的類路徑(classpath)來加載Java應(yīng)用的類。通過ClassLoader.getSystemClassLoader()獲取它。

用戶自定義裝載器(user class loader): 除了系統(tǒng)提供的類裝載器之外,我們還可以通過繼承java.lang.ClassLoader類的方式來實現(xiàn)自己的類裝載器來滿足一些特殊的需求。

類裝載器子系統(tǒng)涉及Java虛擬機的其它組成部分和來自java.lang庫的類。ClassLoader類定義的方法為程序提供了訪問類裝載器機制的接口。對于每個被裝載的類型,Java虛擬機都會給它創(chuàng)建一個java.lang.Class類的實例來代表該類型。和其它對象一樣,用戶自定義的類裝載器以及Class類的實例放在內(nèi)存的堆區(qū),裝載的類型信息位于方法區(qū)。

類裝載器子系統(tǒng)除了要查找定位導(dǎo)入二進制class文件外,還需要負責(zé)驗證被導(dǎo)入的類的正確性,為類的類變量分配并初始化內(nèi)存,以及解析符號引用。順序是:
裝載(查找并裝載類型的二進制數(shù)據(jù))——>連接(驗證:確保被導(dǎo)入類型的正確性,準備:為類變量分配內(nèi)存,并將其初始化為默認值,解析:把類型中的符號引用轉(zhuǎn)換為直接引用)——>初始化(將類變量初始化為正確的初始值)
+----2017-12-16-----+

1. 裝載:裝載是指將編譯后的Java類文件(.class文件)中的二進制數(shù)據(jù)讀入內(nèi)存,并將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個java.lang.Class對象,用其來封裝類在方法區(qū)的數(shù)據(jù)結(jié)構(gòu).即加載后最后得到的是Class對象,該對象是單實例的,即無論這個類創(chuàng)建了多少個對象,他的Class對象是唯一的.通過Class.forName(類的全路徑), 實例對象.class, 實例對象getClass() 這三種可以加載并獲取到該類的Class對象.  
  類裝載時類中的靜態(tài)代碼會被執(zhí)行,例如:Class.forName()加載JDBC驅(qū)動  
2. 連接:靜態(tài)變量的第一次賦值----默認值  
3. 初始化:靜態(tài)變量第二次賦值----真正的初始值 類的初始化發(fā)生在Java程序?qū)︻惖氖状?*主動使用**中,主動使用有(創(chuàng)建類的實例,訪問操作類或接口的靜態(tài)變量,調(diào)用類的靜態(tài)方法,反射如:Class.forName(類全路徑),初始化此類的子類,Java虛擬機啟動時被表明為啟動類的類:java Test),除以上外其他對類的被動使用是不會導(dǎo)致類的初始化.   
執(zhí)行引擎:執(zhí)行字節(jié)碼或者執(zhí)行調(diào)用的本地方法----執(zhí)行引擎的行為由指令集定義

指令集:Java方法的字節(jié)碼流由Java虛擬機的指令序列構(gòu)成。每條指令包含:一個單字節(jié)的操作碼(表示需要執(zhí)行的操作),0或多個操作數(shù)(操作數(shù)向Java虛擬機提供執(zhí)行操作碼的額外信息,使指令使用的值可能來自當(dāng)前常量池中的項,當(dāng)前幀的局部變量中的值或者當(dāng)前操作數(shù)棧頂端的值)。

運行中的Java程序的每一個線程都是一個獨立的虛擬機執(zhí)行引擎的實例。從線程生命周期的開始到結(jié)束,它要么在執(zhí)行字節(jié)碼,要么在執(zhí)行本地方法。

主要的執(zhí)行技術(shù)有:解釋,及時編譯,自適應(yīng)優(yōu)化,芯片級直接執(zhí)行。自適應(yīng)優(yōu)化吸取解釋和及時編譯的優(yōu)點,采取兩種結(jié)合的方式。
自適應(yīng)優(yōu)化——開始對所有的代碼都采取解釋執(zhí)行的方式并監(jiān)視代碼的執(zhí)行情況,然后對那些經(jīng)常調(diào)用的方法啟動一個后臺線程,將其及時編譯為本地代碼進行調(diào)用,并進行仔細優(yōu)化。當(dāng)該方法不再頻繁的被調(diào)用,則取消編譯過的代碼,將其歸為解釋執(zhí)行。

運行時數(shù)據(jù)區(qū):方法區(qū),堆,Java棧,PC寄存器,本地方法棧

方法區(qū)——線程共享

當(dāng)虛擬機裝載某個類型時,它使用類裝載器定位載入相應(yīng)的.class文件到虛擬機中,接著虛擬機提取其中的類型信息,并將這些信息存儲到方法區(qū)。當(dāng)開發(fā)人員在程序中通過Class對象的getName(),isInterface()等方法來獲取信息時,這些數(shù)據(jù)都會來源于方法區(qū),同時方法區(qū)也是全局共享的,在一定條件下它也會被GC掉(虛擬機允許通過用戶自定義的類裝載器來動態(tài)擴展Java程序,此時方法區(qū)也可以被垃圾回收器收集),當(dāng)方法區(qū)需要使用的內(nèi)存超過最大允許時,會拋出OutOfMemory。

方法區(qū)存放內(nèi)容如下:

已經(jīng)被虛擬機所加載的類信息(類名稱,類類型(接口還是類),修飾符,類的直接超類名稱),

類中的靜態(tài)(類)變量,

運行常量池runtime constant pool (類中定義的final類型的常量,一個有序集合,包括直接常量(string,integer,floating 常量)和對其他類型,字段,方法的符號引用)——class文件除了有類信息外,還有一項是常量池(constant pool table),常量池用于存放編譯期生成的各種字面量和符號的引用,這部分內(nèi)容將在類加載后進入方法區(qū)的運行時常量池中存儲。——運行時常量池相對于class文件常量池的一個重要特征是具備動態(tài)性:即除了可以存儲class文件常量池中的內(nèi)容外,運行期間也可能將新的常量放入到池中,比如String類的intern()方法,,參考: 深入理解java虛擬機(三):String.intern()-字符串常量池

類中的方法信息(方法名,返回類型,參數(shù)數(shù)量和類型,修飾符),

字段信息(字段名,類型,修飾符),

指向ClassLoader類的引用(每個類型被裝載時,虛擬機必須跟蹤確定它是由系統(tǒng)類裝載器還是由用戶自定義裝載器裝載的),

指向Class類的引用(對于每隔一個被裝載的類型,虛擬機都為其相應(yīng)的創(chuàng)建了一個java.lang.Class類實例)

----------

堆(heap)——線程共享

堆是JVM用來存儲對象實例以及數(shù)組值(數(shù)組在Java虛擬機中是一個真正的對象)的區(qū)域,可以認為Java中所有通過new創(chuàng)建的對象的內(nèi)存都在堆中分配,堆中的對象所占的內(nèi)存是需要等待GC進行回收的(JVM沒有釋放內(nèi)存的指令,需要將釋放內(nèi)存的任務(wù)交給垃圾收集器處理)。堆是JVM中所有線程共享的。

Java棧(Java stack) ——線程私有,生命周期與線程相同

每當(dāng)啟動一個線程時,Java虛擬機就會為他分配一個Java棧。Java棧由許多棧幀組成,一個棧幀包含一個對應(yīng)的Java方法調(diào)用的狀態(tài)。當(dāng)線程調(diào)用一個Java方法時,虛擬機壓入一個新的棧幀到Java棧中,當(dāng)該方法返回時,這個棧幀就會從Java棧中彈出。

棧幀:由局部變量區(qū),操作數(shù)棧和幀數(shù)據(jù)區(qū)組成。當(dāng)虛擬機調(diào)用一個Java方法時,它從對應(yīng)類的類型信息中得到此方法的局部變量區(qū)和操作數(shù)棧大小,并根據(jù)此來分配幀的內(nèi)存,然后壓入棧中。

局部變量區(qū)

局部變量區(qū)被組織為以字長為單位,從0開始計數(shù)的數(shù)組。字節(jié)碼指令通過從0開始的索引使用其中的數(shù)據(jù)。類型為int, float, reference和returnAddress的值在數(shù)組中占據(jù)一項,而類型為byte, short和char的值在存入數(shù)組前都被轉(zhuǎn)換為int值,也占據(jù)一項。但類型為long和double的值在數(shù)組中卻占據(jù)連續(xù)的兩項。如下圖:

操作數(shù)棧

與局部變量區(qū)一樣,操作數(shù)棧被組織成一個以字長為單位的數(shù)組,其通過標準的棧操作訪問。

幀數(shù)據(jù)區(qū)

Java棧幀需要幀數(shù)據(jù)區(qū)來支持常量池的解析——(每當(dāng)虛擬機要執(zhí)行一個需要操作常量池數(shù)據(jù)的指令時,就會通過幀數(shù)據(jù)區(qū)中指向常量池的指針來訪問常量池),正常方法返回——(幀數(shù)據(jù)區(qū)還要幫助虛擬機處理Java方法的正常結(jié)束或異常中止。如果通過return正常結(jié)束,虛擬機必須恢復(fù)發(fā)起調(diào)用的方法的棧幀,包括設(shè)置程序計數(shù)器指向發(fā)起調(diào)用方法的下一個指令;如果方法有返回值,虛擬機需要將它壓入到發(fā)起調(diào)用的方法的操作數(shù)棧)以及異常派發(fā)機制——(為了處理Java方法執(zhí)行期間的異常退出情況,幀數(shù)據(jù)區(qū)還保存一個對此方法異常表的引用)。

PC寄存器(程序計數(shù)器 program counter)——線程私有,生命周期與線程相同

每一個線程都有它自己的PC寄存器,也是在該線程啟動時創(chuàng)建的。PC寄存器的內(nèi)容總是指向下一條即將被執(zhí)行的指令的地址,這里的地址可以是一個本地地址,也可以是在方法區(qū)中相對于該方法的起始指令的偏移量。

如果線程執(zhí)行Java方法,則PC寄存器保存的是下一條執(zhí)行指令的地址。若線程執(zhí)行的是本地方法,那么此時PC寄存器的值是"undefined"。

本地方法棧(native method stack)——線程私有,生命周期與線程相同

當(dāng)線程調(diào)用Java方法時,虛擬機會創(chuàng)建一個新的棧幀并將其壓入到對應(yīng)線程的Java棧。當(dāng)線程調(diào)用的是本地方法時,虛擬機會保持Java棧不變,不再向Java棧中壓入新的棧幀,虛擬機只是簡單的動態(tài)連接并調(diào)用指定的本地方法。

依賴于本地方法的實現(xiàn),如某個JVM實現(xiàn)的本地方法接口使用C連接模型,則本地方法棧就是C棧,可以說某線程在調(diào)用本地方法時,就進入了一個不受JVM限制的領(lǐng)域,也就是JVM可以利用本地方法來動態(tài)擴展本身。

JVM垃圾回收(Generational Collecting)

GC通過確定對象是否被活動對象引用來確定是否收集回收該對象。

觸發(fā)GC的條件

Java內(nèi)存不足時,GC被調(diào)用。當(dāng)應(yīng)用程序在運行時在運行過程中創(chuàng)建新的對象,若此時內(nèi)存空間不足,就會強制調(diào)用GC線程。若GC一次扔不能滿足內(nèi)存分配,會再次調(diào)用GC,若仍無法滿足要求,則會報錯"out of memory",Java應(yīng)用停止。

GC在優(yōu)先級最低的線程中運行,一般在應(yīng)用程序空閑即沒有應(yīng)用線程在運行的時候被調(diào)用。

兩個重要的方法

System.gc()

使用System.gc()直接請求Java的垃圾回收。

finalize()

在jvm垃圾回收之前調(diào)用的方法。之所有要使用finalize(),是存在著垃圾回收器不能處理的情況:1) 在本地方法native method調(diào)用中,可能由于在分配內(nèi)存的時候可能采用了類似C語言的做法,而非Java的new做法,比如本地方法調(diào)用了C++的malloc()來分配內(nèi)存而沒有調(diào)用free()來釋放掉內(nèi)存,這時候就可能造成內(nèi)存泄露。這時就可以在finalize()方法中用本地方法調(diào)用free()來釋放掉這些特殊的內(nèi)存空間。 2)又或者是打開了文件資源,這些資源不屬于垃圾回收器能回收的范圍,則需要在finalize()中調(diào)用對應(yīng)的本地方法來回收文件資源。

減少GC開銷的措施

不要顯式調(diào)用System.gc()。此函數(shù)建議JVM進行主GC,雖然只是建議而非一定,但很多情況下它會觸發(fā)主GC,從而增加主GC的頻率,也即增加了間歇性停頓的次數(shù)。大大的影響系統(tǒng)性能。

減少對臨時對象的使用。臨時對象在方法結(jié)束后會成為垃圾,很快創(chuàng)建很快結(jié)束,增加了GC開銷。

對象不用時最好置為NULL。NULL對象一般都會作為垃圾處理,把不用的對象置為NULL有利于GC判定垃圾效率。

能用基本類型int long,就不要new Integet,new Long對象?;绢愋驼加脙?nèi)存資源相應(yīng)較小。

少用靜態(tài)對象變量。靜態(tài)對象變量屬于全局變量,不會被GC回收,他們會一直占用內(nèi)存空間。

字符串修改用StringBuffer,StringBuilder,不用String。

避免大量集中new新對象。

對象在jvm堆區(qū)的狀態(tài)

可觸及狀態(tài):程序中還有變量引用,那么此對象為可觸及狀態(tài)。

可復(fù)活狀態(tài):當(dāng)程序中已經(jīng)沒有變量引用這個對象,那么此對象由可觸及狀態(tài)轉(zhuǎn)為可復(fù)活狀態(tài)。CG線程將在一定的時間準備調(diào)用此對象的finalize方法(finalize方法繼承或重寫子Object),finalize方法內(nèi)的代碼有可能將對象轉(zhuǎn)為可觸及狀態(tài),否則對象轉(zhuǎn)化為不可觸及狀態(tài)。

不可觸及狀態(tài):只有當(dāng)對象處于不可觸及狀態(tài)時,GC線程才能回收此對象的內(nèi)存。

常用垃圾收集器

標記-清除收集器 mark-sweep

復(fù)制收集器 copying

標記-壓縮收集器 mark-compact

分代收集器 generational

垃圾收集算法 tracing算法

基于tracing算法的垃圾回收也稱為標記和清除(mark-sweep)垃圾收集器。
標記-清除算法分為兩個階段:標記階段和清除階段。標記階段的任務(wù)是標記出所有的需要被回收的對象,清除階段就是回收被標記的對象所占用的內(nèi)存空間。
此算法缺陷就是很容易產(chǎn)生內(nèi)存碎片,在產(chǎn)生大量的內(nèi)存碎片后就可能無法對新的大對象所需要的內(nèi)存空間進行分配。

copying算法

為了解決標記-清除算法的缺陷,coping算法是將內(nèi)存按內(nèi)存容量劃分為大小相等的兩塊,每次對新對象的內(nèi)存分配只使用其中的一塊。當(dāng)這一塊內(nèi)存用完的時候,就將在這塊內(nèi)存上還存活下來的對象復(fù)制到另以空閑塊內(nèi)存上面,然后把那塊已經(jīng)使用的內(nèi)存空間全部清理。
此算法雖然不會產(chǎn)生內(nèi)存碎片,但是每次只能使用一半的內(nèi)存空間,降低了內(nèi)存實際使用率。而且當(dāng)存活的對象還很多的時候,需要將它們?nèi)繌?fù)制到另一塊內(nèi)存上,這也使效率降低。

compating算法

為了解決compying算法的缺陷而充分的利用內(nèi)存空間,提出了mark-compact 算法,即標記-壓縮。該算法的標記階段和mark-sweep一樣將所有需要被回收的對象進行標記。但是標記完成后,它不是直接清理可回收對象,而是將存活的對象都向一端移動,然后清理掉存活對象邊界以外的內(nèi)存空間。這樣即不會產(chǎn)生內(nèi)碎片,也充分利用了內(nèi)存空間。

generation算法

分代收集算法是目前大部分jvm的垃圾回收器所采用的算法。它的核心思想是根據(jù)對象存活的生命周期來劃分不同的區(qū)域,對每個區(qū)域進行不用的垃圾回收策略。一般情況將堆區(qū)分為老年代(tenured generation)和新生代(young generation) ,老年代的特點是每次垃圾回收時只會有少量的對象需要被回收,而新生代的特點是每次垃圾回收時都會有大量的對象需要被回收掉。

目前大部分垃圾收集器對于新生代都采取Copying算法,因為新生代中每次垃圾回收都要回收大部分對象,也就是說需要復(fù)制的操作次數(shù)較少,但是實際中并不是按照1:1的比例來劃分新生代的空間的,一般來說是將新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當(dāng)進行回收時,將Eden和Survivor中還存活的對象復(fù)制到另一塊Survivor空間中,然后清理掉Eden和剛才使用過的Survivor空間。

而由于老年代的特點是每次回收都只回收少量對象,一般使用的是Mark-Compact算法。

新生代:新創(chuàng)建的對象都存放在這里。因為大多數(shù)對象很快變得不可達,所以大多數(shù)對象在年輕代中創(chuàng)建,然后消失。當(dāng)對象從這塊內(nèi)存區(qū)域消失時,我們說發(fā)生了一次“minor GC”。

老年代:沒有變得不可達,存活下來的年輕代對象被復(fù)制到這里。這塊內(nèi)存區(qū)域一般大于年輕代。因為它更大的規(guī)模,GC發(fā)生的次數(shù)比在年輕代的少。對象從老年代消失時,我們說 "major GC"("full GC")。

永久代(permanent generation)也稱為“方法區(qū)(method area)”,他存儲class對象和字符串常量。所以這塊內(nèi)存區(qū)域絕對不是永久的存放從老年代存活下來的對象的。在這塊內(nèi)存中有可能發(fā)生垃圾回收。發(fā)生在這里垃圾回收也被稱為major GC。


參考來自
深入理解Java虛擬機體系結(jié)構(gòu)
什么是JVM?
面試準備之JVM的組成、垃圾回收機制
深入理解Java虛擬機
深入理解JVM--JVM垃圾回收機制



分享一波阿里云代金券快速上云

from usthe.com

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68974.html

相關(guān)文章

  • 《深入理解java虛擬學(xué)習(xí)筆記系列——java內(nèi)存區(qū)域劃分

    摘要:運行時數(shù)據(jù)區(qū)域的學(xué)習(xí),是學(xué)習(xí)以及機制的基礎(chǔ),也是深入理解對象創(chuàng)建及運行過程的前提。了解內(nèi)存區(qū)域劃分,是學(xué)習(xí)概念的前提。 Java 運行時數(shù)據(jù)區(qū)域的學(xué)習(xí),是學(xué)習(xí) jvm 以及 GC 機制的基礎(chǔ),也是深入理解 java 對象創(chuàng)建及運行過程的前提。廢話不多說,直接進入正題: 一張圖總結(jié) showImg(https://segmentfault.com/img/bVOMAn?w=685&h=5...

    史占廣 評論0 收藏0
  • 學(xué)習(xí)JVM必看書籍

    學(xué)習(xí)JVM的相關(guān)資料 《深入理解Java虛擬機——JVM高級特性與最佳實踐(第2版)》 showImg(https://segmentfault.com/img/bVbsqF5?w=200&h=200); 基于最新JDK1.7,圍繞內(nèi)存管理、執(zhí)行子系統(tǒng)、程序編譯與優(yōu)化、高效并發(fā)等核心主題對JVM進行全面而深入的分析,深刻揭示JVM的工作原理。以實踐為導(dǎo)向,通過大量與實際生產(chǎn)環(huán)境相結(jié)合的案例展示了解...

    shaonbean 評論0 收藏0
  • 從表到里學(xué)習(xí)JVM實現(xiàn)

    在社會化分工、軟件行業(yè)細分專業(yè)化的趨勢下,會真的參與到底層系統(tǒng)實現(xiàn)的人肯定是越來越少(比例上說)。真的會參與到JVM實現(xiàn)的人肯定是少數(shù)。 但如果您對JVM是如何實現(xiàn)的有興趣、充滿好奇,卻苦于沒有足夠系統(tǒng)的知識去深入,那么可以參考RednaxelaFX整理的這個書單。 showImg(http://segmentfault.com/img/bVbGzn); 本豆列的脈絡(luò)是:    1. JV...

    Cristic 評論0 收藏0
  • JVM學(xué)習(xí)-Java內(nèi)存區(qū)域職責(zé)(1)

    摘要:此內(nèi)存區(qū)域是唯一一個在虛擬機規(guī)范中沒有規(guī)定任何情況的區(qū)域。其中位長度的和類型的數(shù)據(jù)會占用個局部變量空間,其余數(shù)據(jù)類型只占用個。內(nèi)存區(qū)域異常線程請求棧深度大于虛擬機允許的深度,將拋出。上限控制異常直接內(nèi)存 showImg(https://segmentfault.com/img/bVbundc?w=800&h=559); 運行時數(shù)據(jù)區(qū)域 程序計數(shù)器 線程正在執(zhí)行時,如果執(zhí)行的是一個Jav...

    xiaochao 評論0 收藏0
  • 《深入理解java虛擬學(xué)習(xí)筆記系列——對象的內(nèi)存布局

    摘要:上一篇文章講解了虛擬機中的內(nèi)存布局,這里就稍作拓展,聊聊對象在虛擬機中的一些存儲細節(jié)吧。參考文檔深入理解虛擬機高級特效與最佳實現(xiàn),第章周志明著系列筆記內(nèi)存區(qū)域和機制明舞深入理解結(jié)構(gòu)團長聯(lián)系作者 上一篇文章講解了 java 虛擬機中的內(nèi)存布局,這里就稍作拓展,聊聊 java 對象在虛擬機中的一些存儲細節(jié)吧。 本文主要圍繞虛擬機中對象如何創(chuàng)建?對象內(nèi)存都放些什么?如何訪問對象內(nèi)存?這么三...

    miya 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<