java文件读入原理_描述一下JVM加载class文件的原理机制
1、JVM?簡介
JVM?是我們Javaer?的最基本功底了,剛開始學(xué)Java?的時候,一般都是從“Hello World?”開始的,然后會寫個復(fù)雜點class?,然后再找一些開源框架,比如Spring?,Hibernate?等等,再然后就開發(fā)企業(yè)級的應(yīng)用,比如網(wǎng)站、企業(yè)內(nèi)部應(yīng)用、實時交易系統(tǒng)等等,直到某一天突然發(fā)現(xiàn)做的系統(tǒng)咋就這么慢呢,而且時不時還來個內(nèi)存溢出什么的,今天是交易系統(tǒng)報了StackOverflowError?,明天是網(wǎng)站系統(tǒng)報了個OutOfMemoryError?,這種錯誤又很難重現(xiàn),只有分析Javacore?和dump?文件,運氣好點還能分析出個結(jié)果,運行遭的點,就直接去廟里燒香吧!每天接客戶的電話都是戰(zhàn)戰(zhàn)兢兢的,生怕再出什么幺蛾子了。我想Java?做的久一點的都有這樣的經(jīng)歷,那這些問題的最終根結(jié)是在哪呢?——?JVM?。
JVM?全稱是Java Virtual Machine?,Java?虛擬機,也就是在計算機上再虛擬一個計算機,這和我們使用?VMWare不一樣,那個虛擬的東西你是可以看到的,這個JVM?你是看不到的,它存在內(nèi)存中。我們知道計算機的基本構(gòu)成是:運算器、控制器、存儲器、輸入和輸出設(shè)備,那這個JVM?也是有這成套的元素,運算器是當(dāng)然是交給硬件CPU?還處理了,只是為了適應(yīng)“一次編譯,隨處運行”的情況,需要做一個翻譯動作,于是就用了JVM?自己的命令集,這與匯編的命令集有點類似,每一種匯編命令集針對一個系列的CPU?,比如8086?系列的匯編也是可以用在8088?上的,但是就不能跑在8051?上,而JVM?的命令集則是可以到處運行的,因為JVM?做了翻譯,根據(jù)不同的CPU?,翻譯成不同的機器語言。
JVM?中我們最需要深入理解的就是它的存儲部分,存儲?硬盤?NO?,NO?,?JVM?是一個內(nèi)存中的虛擬機,那它的存儲就是內(nèi)存了,我們寫的所有類、常量、變量、方法都在內(nèi)存中,這決定著我們程序運行的是否健壯、是否高效,接下來的部分就是重點介紹之。
2、JVM?的組成部分
我們先把JVM?這個虛擬機畫出來,如下圖所示:
從這個圖中可以看到,JVM?是運行在操作系統(tǒng)之上的,它與硬件沒有直接的交互。我們再來看下JVM?有哪些組成部分,如下圖所示:
該圖參考了網(wǎng)上廣為流傳的JVM?構(gòu)成圖,大家看這個圖,整個JVM?分為四部分:
## Class Loader?類加載器
類加載器的作用是加載類文件到內(nèi)存,比如編寫一個HelloWord.java?程序,然后通過javac?編譯成class?文件,那怎么才能加載到內(nèi)存中被執(zhí)行呢?Class Loader?承擔(dān)的就是這個責(zé)任,那不可能隨便建立一個.class?文件就能被加載的,Class Loader?加載的class?文件是有格式要求,在《JVM Specification?》中式這樣定義Class?文件的結(jié)構(gòu):
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
需要詳細(xì)了解的話,可以仔細(xì)閱讀《JVM Specification?》的第四章“The class File Format?”,這里不再詳細(xì)說明。
友情提示:Class Loader?只管加載,只要符合文件結(jié)構(gòu)就加載,至于說能不能運行,則不是它負(fù)責(zé)的,那是由Execution Engine?負(fù)責(zé)的。
##?Execution Engine?執(zhí)行引擎
執(zhí)行引擎也叫做解釋器(Interpreter)?,負(fù)責(zé)解釋命令,提交操作系統(tǒng)執(zhí)行。
##?Native Interface?本地接口
本地接口的作用是融合不同的編程語言為Java?所用,它的初衷是融合C/C++?程序,Java?誕生的時候是C/C++?橫行的時候,要想立足,必須有一個聰明的、睿智的調(diào)用C/C++?程序,于是就在內(nèi)存中專門開辟了一塊區(qū)域處理標(biāo)記為native?的代碼,它的具體做法是Native Method Stack?中登記native?方法,在Execution Engine?執(zhí)行時加載native libraies?。目前該方法使用的是越來越少了,除非是與硬件有關(guān)的應(yīng)用,比如通過Java?程序驅(qū)動打印機,或者Java?系統(tǒng)管理生產(chǎn)設(shè)備,在企業(yè)級應(yīng)用中已經(jīng)比較少見,因為現(xiàn)在的異構(gòu)領(lǐng)域間的通信很發(fā)達(dá),比如可以使用Socket?通信,也可以使用Web Service?等等,不多做介紹。
## Runtime data area?運行數(shù)據(jù)區(qū)
運行數(shù)據(jù)區(qū)是整個JVM?的重點。我們所有寫的程序都被加載到這里,之后才開始運行,Java?生態(tài)系統(tǒng)如此的繁榮,得益于該區(qū)域的優(yōu)良自治。
整個JVM?框架由加載器加載文件,然后執(zhí)行器在內(nèi)存中處理數(shù)據(jù),需要與異構(gòu)系統(tǒng)交互是可以通過本地接口進(jìn)行,瞧,一個完整的系統(tǒng)誕生了!
3、JVM加載class文件的原理機制
Java中的所有類,都需要由類加載器裝載到JVM中才能運行。類加載器本身也是一個類,而它的工作就是把class文件從硬盤讀取到內(nèi)存中。在寫程序的時候,我們幾乎不需要關(guān)心類的加載,因為這些都是隱式裝載的,除非我們有特殊的用法,像是反射,就需要顯式的加載所需要的類。
類裝載方式,有兩種
1.隱式裝載, 程序在運行過程中當(dāng)碰到通過new 等方式生成對象時,隱式調(diào)用類裝載器加載對應(yīng)的類到j(luò)vm中,
2.顯式裝載, 通過class.forname()等方法,顯式加載需要的類
隱式加載與顯式加載的區(qū)別:兩者本質(zhì)是一樣?
Java類的加載是動態(tài)的,它并不會一次性將所有類全部加載后再運行,而是保證程序運行的基礎(chǔ)類(像是基類)完全加載到j(luò)vm中,至于其他類,則在需要的時候才加載。這當(dāng)然就是為了節(jié)省內(nèi)存開銷。
Java的類加載器有三個,對應(yīng)Java的三種類:(java中的類大致分為三種:?? 1.系統(tǒng)類?? 2.擴展類?3.由程序員自定義的類?)
Bootstrap Loader? // 負(fù)責(zé)加載系統(tǒng)類?(指的是內(nèi)置類,像是String,對應(yīng)于C#中的System類和C/C++標(biāo)準(zhǔn)庫中的類)
|
- - ExtClassLoader?? //?負(fù)責(zé)加載擴展類(就是繼承類和實現(xiàn)類)
|
- - AppClassLoader?? //?負(fù)責(zé)加載應(yīng)用類(程序員自定義的類)
三個加載器各自完成自己的工作,但它們是如何協(xié)調(diào)工作呢?哪一個類該由哪個類加載器完成呢?為了解決這個問題,Java采用了委托模型機制。
委托模型機制的工作原理很簡單:當(dāng)類加載器需要加載類的時候,先請示其Parent(即上一層加載器)在其搜索路徑載入,如果找不到,才在自己的搜索路徑搜索該類。這樣的順序其實就是加載器層次上自頂而下的搜索,因為加載器必須保證基礎(chǔ)類的加載。之所以是這種機制,還有一個安全上的考慮:如果某人將一個惡意的基礎(chǔ)類加載到j(luò)vm,委托模型機制會搜索其父類加載器,顯然是不可能找到的,自然就不會將該類加載進(jìn)來。
我們可以通過這樣的代碼來獲取類加載器:
ClassLoader loader = ClassName.class.getClassLoader();
ClassLoader ParentLoader = loader.getParent();
注意一個很重要的問題,就是Java在邏輯上并不存在BootstrapKLoader的實體!因為它是用C++編寫的,所以打印其內(nèi)容將會得到null。
前面是對類加載器的簡單介紹,它的原理機制非常簡單,就是下面幾個步驟:
1.裝載:查找和導(dǎo)入class文件;
2.連接:
(1)檢查:檢查載入的class文件數(shù)據(jù)的正確性;
(2)準(zhǔn)備:為類的靜態(tài)變量分配存儲空間;
(3)解析:將符號引用轉(zhuǎn)換成直接引用(這一步是可選的)
3.初始化:初始化靜態(tài)變量,靜態(tài)代碼塊。
這樣的過程在程序調(diào)用類的靜態(tài)成員的時候開始執(zhí)行,所以靜態(tài)方法main()才會成為一般程序的入口方法。類的構(gòu)造器也會引發(fā)該動作。
總結(jié)
以上是生活随笔為你收集整理的java文件读入原理_描述一下JVM加载class文件的原理机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea的setting界面怎么进_电脑
- 下一篇: c 多文件全局变量_C语言开发单片机为什