摘要:java是當(dāng)前比較火的一門編程語言,由于java的跨平臺性使得java的應(yīng)用在越來越多的方面得以體現(xiàn),在java大行其道的背后有著一個(gè)默默無聞的工作角色,這個(gè)角色就是java虛擬機(jī)——JVM,在本文中對JVM的運(yùn)行過程做了一些研究,并綜合闡述了JVM的運(yùn)行部件和運(yùn)行機(jī)制。
關(guān)鍵詞:JVM java虛擬機(jī) 跨平臺 面向?qū)ο缶幊?/p>
Java因?yàn)槠淞己玫目缙脚_性,得到越來越多程序員的喜歡,同時(shí)隨著智能化家居的日益普及,java已經(jīng)從開發(fā)的神壇走向平常百姓身邊。無時(shí)無刻我們的身邊都有java設(shè)備的運(yùn)行,網(wǎng)絡(luò)電視中的android平臺,運(yùn)行在其上的各種APP都是java運(yùn)行的結(jié)果,車載系統(tǒng)已經(jīng)從原先最早的嵌入式形式走向現(xiàn)在更具體的獨(dú)立系統(tǒng)階段,裝上android系統(tǒng),各種應(yīng)用便可以進(jìn)行拓展,不得不說,java已經(jīng)是我們親密的伙伴和朋友。但是在此不得不說,一個(gè)非常重要的幕后英雄,JVM(java虛擬機(jī)Java Virtual Machine)。
總所周知,操作系統(tǒng)封裝了底層的硬件設(shè)備,為人們使用計(jì)算機(jī)設(shè)備提供了人性化接口,為編程提供了各種API調(diào)用接口,但是各種操作系統(tǒng)在給人們提供便利的同時(shí),又因?yàn)楸舜说牟煌?,給開發(fā)應(yīng)用系統(tǒng)帶來一定的阻礙,因?yàn)獒槍σ环N系統(tǒng)的應(yīng)用要運(yùn)行在另外一個(gè)系統(tǒng)上的話,必然要在此開發(fā)針對另外系統(tǒng)的應(yīng)用,增加了人們的開發(fā)工作量。為了解決這一問題,Sun公司開發(fā)了java語言,當(dāng)然其初衷并非如此,但是確實(shí)也達(dá)到了這樣的目的,至于其初衷在此不做討論。Java語言使用Java虛擬機(jī)屏蔽了與具體平臺相關(guān)的信息,使得Java語言編譯程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運(yùn)行。JVM是java的核心和基礎(chǔ),它是建立在java編譯器和操作系統(tǒng)平臺之間的虛擬電腦,或者狹義的理解為虛擬處理器,其運(yùn)行基于下層操作系統(tǒng)和硬件平臺通過軟件來實(shí)現(xiàn)的抽象的計(jì)算機(jī)。java編譯器只需根據(jù)JVM編譯即可,程序員可以根據(jù)統(tǒng)一的標(biāo)準(zhǔn)去編寫程序,讓更做的重點(diǎn)放在工作流和業(yè)務(wù)流上。編譯器只需生成JVM能理解的代碼或者字節(jié)碼文件即可,JRE(java運(yùn)行環(huán)境)將每一條指令翻譯成不同平臺的機(jī)器碼,保證其在不同平臺上的運(yùn)行。
一個(gè)程序從源代碼到運(yùn)行的執(zhí)行過程如下:
1.編寫java源文件。
2.Javac編譯器將源文件編譯成class文件。
3.加載.class文件。
然后虛擬機(jī)采用如下圖所示的處理過程執(zhí)行程序:
下面對JVM的運(yùn)行組成做個(gè)說明:
1.JVM指令系統(tǒng)
JVM是對底層系統(tǒng)的抽象,同計(jì)算機(jī)指令系統(tǒng)一樣,JVM提供指令系統(tǒng),其指令也是由操作碼和操作數(shù)兩部分構(gòu)成,JVM操作碼是8位二進(jìn)制數(shù),所以JVM提供醉倒256種指令,已經(jīng)使用160多種。
2.JVM寄存器
在普通的操作系統(tǒng)中,CPU包含一定的寄存器,JVM也設(shè)置了幾種常用的寄存器,PC程序計(jì)數(shù)器,OPTOP操作數(shù)棧頂指針,F(xiàn)RAM當(dāng)前執(zhí)行環(huán)境指針,VARS指向當(dāng)前執(zhí)行環(huán)境第一個(gè)局部變量的指針。其中所有 寄存器都是32位,PC記錄程序的執(zhí)行,其他幾個(gè)寄存器記錄指向java棧區(qū)的指針。
其中,PC程序計(jì)數(shù)器可以理解為當(dāng)前線程所執(zhí)行的字節(jié)碼行號指示器,在JVM概念模型中,字節(jié)碼解釋器通過改變計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理等都依賴于程序計(jì)數(shù)器。
3.堆棧結(jié)構(gòu)以及存儲區(qū)
JVM主要用棧來存儲信息,當(dāng)JVM得到.class的字節(jié)碼后便為該代碼中一個(gè)類的每個(gè)方法創(chuàng)建一個(gè)包含局部變量、執(zhí)行環(huán)境、操作數(shù)的??蚣堋?,VARS寄存器指向局部變量中第一個(gè)變量的位置。操作數(shù)棧主要用于保存運(yùn)算所需要的操作數(shù)以及運(yùn)算的結(jié)果,執(zhí)行的時(shí)候從棧頂彈出操作數(shù)進(jìn)行運(yùn)算,最后將運(yùn)算結(jié)果壓人棧頂。解釋器具體承擔(dān)實(shí)例空間的分配工作,解釋器為實(shí)例分配完存儲空間后就可以記錄該實(shí)例所占用的內(nèi)存區(qū)域的使用,一旦對象使用完畢就將其回收到堆中。也就是使用NEW語句構(gòu)造出來的對象最終要存在堆上,如果不再使用則由垃圾回收機(jī)制回收,即堆是java垃圾收集器管理的主要區(qū)域,所以很多時(shí)候它稱為GC區(qū)。為了存放類名稱、方法和字段名稱以及串常量,這些元素存放在JVM中的常量緩沖池,Java方法的字節(jié)碼則存放在方法區(qū)。
4.垃圾回收機(jī)制
使用過C++編程的人一定會為C++中內(nèi)存泄漏而苦惱,因?yàn)镃++運(yùn)行環(huán)境中,對象所占的內(nèi)存在程序結(jié)束后不會主動(dòng)釋放,其釋放必須通過程序員調(diào)用代碼釋放,而在Java中有完善的垃圾回收機(jī)制,在對象引用沒有指向原先分配給某個(gè)對象的內(nèi)存時(shí),便忍者這塊內(nèi)存便成是垃圾。JVM的一個(gè)系統(tǒng)級線程會自動(dòng)釋放該內(nèi)存塊。垃圾回收意味著程序不再需要的對象是“無用信息”,這些信息將被丟棄。當(dāng)一個(gè)對象不再被引用的時(shí)候,內(nèi)存回收它占領(lǐng)的空間,以便空間被后來的新對象使用。事實(shí)上,除了釋放沒用的對象,垃圾回收也可以清除內(nèi)存記錄碎片。由于創(chuàng)建對象和垃圾回收器釋放丟棄對象所占的內(nèi)存空間,內(nèi)存會出現(xiàn)碎片。碎片是分配給對象的內(nèi)存塊之間的空閑內(nèi)存洞。碎片整理將所占用的堆內(nèi)存移到堆的一端,JVM將整理出的內(nèi)存分配給新的對象。垃圾回收能自動(dòng)釋放內(nèi)存空間,減輕編程的負(fù)擔(dān)。這使Java 虛擬機(jī)具有一些優(yōu)點(diǎn)。首先,它能使編程效率提高。在沒有垃圾回收機(jī)制的時(shí)候,可能要花許多時(shí)間來解決一個(gè)難懂的存儲器問題。在用Java語言編程的時(shí)候,靠垃圾回收機(jī)制可大大縮短時(shí)間。其次是它保護(hù)程序的完整性,垃圾回收是Java語言安全性策略的一個(gè)重要部份。
經(jīng)常有人說java的執(zhí)行效率低,畢竟因?yàn)閖ava是在底層的基礎(chǔ)之上做了一層封裝,其實(shí)現(xiàn)在經(jīng)過JVM的優(yōu)化,只要站在底層運(yùn)行的角度去編寫代碼、優(yōu)化代碼和其他編譯性程序語言相比,這種差距也越來越小,相比于JVM帶來的極大便利,這點(diǎn)差距又算得了什么呢。
(作者簡介:張衛(wèi),碩士研究生學(xué)歷,計(jì)算機(jī)科學(xué)與技術(shù)專業(yè),銅仁幼兒師范高等??茖W(xué)校講師,研究方向有:網(wǎng)格計(jì)算,計(jì)算機(jī)軟件與程序設(shè)計(jì),多年從事一線教育工作和知名大學(xué)計(jì)算機(jī)實(shí)訓(xùn)培訓(xùn)工作。)