日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

慢慢琢磨JVM

發(fā)布時(shí)間:2023/12/19 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 慢慢琢磨JVM 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 JVM簡(jiǎn)介

JVM是我們Javaer的最基本功底了,剛開始學(xué)Java的時(shí)候,一般都是從“Hello World”開始的,然后會(huì)寫個(gè)復(fù)雜點(diǎn)class,然后再找一些開源框架,比如Spring,Hibernate等等,再然后就開發(fā)企業(yè)級(jí)的應(yīng)用,比如網(wǎng)站、企業(yè)內(nèi)部應(yīng)用、實(shí)時(shí)交易系統(tǒng)等等,直到某一天突然發(fā)現(xiàn)做的系統(tǒng)咋就這么慢呢,而且時(shí)不時(shí)還來個(gè)內(nèi)存溢出什么的,今天是交易系統(tǒng)報(bào)了StackOverflowError,明天是網(wǎng)站系統(tǒng)報(bào)了個(gè)OutOfMemoryError,這種錯(cuò)誤又很難重現(xiàn),只有分析Javacore和dump文件,運(yùn)氣好點(diǎn)還能分析出個(gè)結(jié)果,運(yùn)行遭的點(diǎn),就直接去廟里燒香吧!每天接客戶的電話都是戰(zhàn)戰(zhàn)兢兢的,生怕再出什么幺蛾子了。我想Java做的久一點(diǎn)的都有這樣的經(jīng)歷,那這些問題的最終根結(jié)是在哪呢?——?JVM。

JVM全稱是Java VirtualMachine,Java虛擬機(jī),也就是在計(jì)算機(jī)上再虛擬一個(gè)計(jì)算機(jī),這和我們使用?VMWare不一樣,那個(gè)虛擬的東西你是可以看到的,這個(gè)JVM你是看不到的,它存在內(nèi)存中。我們知道計(jì)算機(jī)的基本構(gòu)成是:運(yùn)算器、控制器、存儲(chǔ)器、輸入和輸出設(shè)備,那這個(gè)JVM也是有這成套的元素,運(yùn)算器是當(dāng)然是交給硬件CPU還處理了,只是為了適應(yīng)“一次編譯,隨處運(yùn)行”的情況,需要做一個(gè)翻譯動(dòng)作,于是就用了JVM自己的命令集,這與匯編的命令集有點(diǎn)類似,每一種匯編命令集針對(duì)一個(gè)系列的CPU,比如8086系列的匯編也是可以用在8088上的,但是就不能跑在8051上,而JVM的命令集則是可以到處運(yùn)行的,因?yàn)镴VM做了翻譯,根據(jù)不同的CPU,翻譯成不同的機(jī)器語(yǔ)言。

JVM中我們最需要深入理解的就是它的存儲(chǔ)部分,存儲(chǔ)?硬盤?NO,NO,?JVM是一個(gè)內(nèi)存中的虛擬機(jī),那它的存儲(chǔ)就是內(nèi)存了,我們寫的所有類、常量、變量、方法都在內(nèi)存中,這決定著我們程序運(yùn)行的是否健壯、是否高效,接下來的部分就是重點(diǎn)介紹之。

2 JVM的組成部分

我們先把JVM這個(gè)虛擬機(jī)畫出來,如下圖所示:



從這個(gè)圖中可以看到,JVM是運(yùn)行在操作系統(tǒng)之上的,它與硬件沒有直接的交互。我們?cè)賮砜聪翵VM有哪些組成部分,如下圖所示:



?該圖參考了網(wǎng)上廣為流傳的JVM構(gòu)成圖,大家看這個(gè)圖,整個(gè)JVM分為四部分:

q??Class Loader?類加載器

類加載器的作用是加載類文件到內(nèi)存,比如編寫一個(gè)HelloWord.java程序,然后通過javac編譯成class文件,那怎么才能加載到內(nèi)存中被執(zhí)行呢?Class Loader承擔(dān)的就是這個(gè)責(zé)任,那不可能隨便建立一個(gè).class文件就能被加載的,Class Loader加載的class文件是有格式要求,在《JVM Specification》中式這樣定義Class文件的結(jié)構(gòu):

????ClassFile {

??????u4 magic;

??????u2 minor_version;

??????u2 major_version;

??????u2 constant_pool_count;

??????cp_infoconstant_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_infoattributes[attributes_count];

????}

需要詳細(xì)了解的話,可以仔細(xì)閱讀《JVM Specification》的第四章“The class File Format”,這里不再詳細(xì)說明。

友情提示:Class Loader只管加載,只要符合文件結(jié)構(gòu)就加載,至于說能不能運(yùn)行,則不是它負(fù)責(zé)的,那是由Execution Engine負(fù)責(zé)的。

q??Execution Engine?執(zhí)行引擎

執(zhí)行引擎也叫做解釋器(Interpreter),負(fù)責(zé)解釋命令,提交操作系統(tǒng)執(zhí)行。

q??Native Interface本地接口

本地接口的作用是融合不同的編程語(yǔ)言為Java所用,它的初衷是融合C/C++程序,Java誕生的時(shí)候是C/C++橫行的時(shí)候,要想立足,必須有一個(gè)聰明的、睿智的調(diào)用C/C++程序,于是就在內(nèi)存中專門開辟了一塊區(qū)域處理標(biāo)記為native的代碼,它的具體做法是Native Method Stack中登記native方法,在Execution Engine執(zhí)行時(shí)加載native libraies。目前該方法使用的是越來越少了,除非是與硬件有關(guān)的應(yīng)用,比如通過Java程序驅(qū)動(dòng)打印機(jī),或者Java系統(tǒng)管理生產(chǎn)設(shè)備,在企業(yè)級(jí)應(yīng)用中已經(jīng)比較少見,因?yàn)楝F(xiàn)在的異構(gòu)領(lǐng)域間的通信很發(fā)達(dá),比如可以使用Socket通信,也可以使用Web Service等等,不多做介紹。

q??Runtime data area運(yùn)行數(shù)據(jù)區(qū)

運(yùn)行數(shù)據(jù)區(qū)是整個(gè)JVM的重點(diǎn)。我們所有寫的程序都被加載到這里,之后才開始運(yùn)行,Java生態(tài)系統(tǒng)如此的繁榮,得益于該區(qū)域的優(yōu)良自治,下一章節(jié)詳細(xì)介紹之。

?

整個(gè)JVM框架由加載器加載文件,然后執(zhí)行器在內(nèi)存中處理數(shù)據(jù),需要與異構(gòu)系統(tǒng)交互是可以通過本地接口進(jìn)行,瞧,一個(gè)完整的系統(tǒng)誕生了!

2 JVM的內(nèi)存管理

所有的數(shù)據(jù)和程序都是在運(yùn)行數(shù)據(jù)區(qū)存放,它包括以下幾部分:

q??Stack?棧

棧也叫棧內(nèi)存,是Java程序的運(yùn)行區(qū),是在線程創(chuàng)建時(shí)創(chuàng)建,它的生命期是跟隨線程的生命期,線程結(jié)束棧內(nèi)存也就釋放,對(duì)于棧來說不存在垃圾回收問題,只要線程一結(jié)束,該棧就Over。問題出來了:棧中存的是那些數(shù)據(jù)呢?又什么是格式呢?

棧中的數(shù)據(jù)都是以棧幀(Stack Frame)的格式存在,棧幀是一個(gè)內(nèi)存區(qū)塊,是一個(gè)數(shù)據(jù)集,是一個(gè)有關(guān)方法(Method)和運(yùn)行期數(shù)據(jù)的數(shù)據(jù)集,當(dāng)一個(gè)方法A被調(diào)用時(shí)就產(chǎn)生了一個(gè)棧幀F(xiàn)1,并被壓入到棧中,A方法又調(diào)用了B方法,于是產(chǎn)生棧幀F(xiàn)2也被壓入棧,執(zhí)行完畢后,先彈出F2棧幀,再?gòu)棾鯢1棧幀,遵循“先進(jìn)后出”原則。

那棧幀中到底存在著什么數(shù)據(jù)呢?棧幀中主要保存3類數(shù)據(jù):本地變量(LocalVariables),包括輸入?yún)?shù)和輸出參數(shù)以及方法內(nèi)的變量;棧操作(Operand Stack),記錄出棧、入棧的操作;棧幀數(shù)據(jù)(FrameData),包括類文件、方法等等。光說比較枯燥,我們畫個(gè)圖來理解一下Java棧,如下圖所示:



?圖示在一個(gè)棧中有兩個(gè)棧幀,棧幀2是最先被調(diào)用的方法,先入棧,然后方法2又調(diào)用了方法1,棧幀1處于棧頂?shù)奈恢?#xff0c;棧幀2處于棧底,執(zhí)行完畢后,依次彈出棧幀1和棧幀2,線程結(jié)束,棧釋放。

q??Heap?堆內(nèi)存

一個(gè)JVM實(shí)例只存在一個(gè)堆類存,堆內(nèi)存的大小是可以調(diào)節(jié)的。類加載器讀取了類文件后,需要把類、方法、常變量放到堆內(nèi)存中,以方便執(zhí)行器執(zhí)行,堆內(nèi)存分為三部分:

Permanent Space?永久存儲(chǔ)區(qū)

永久存儲(chǔ)區(qū)是一個(gè)常駐內(nèi)存區(qū)域,用于存放JDK自身所攜帶的Class,Interface的元數(shù)據(jù),也就是說它存儲(chǔ)的是運(yùn)行環(huán)境必須的類信息,被裝載進(jìn)此區(qū)域的數(shù)據(jù)是不會(huì)被垃圾回收器回收掉的,關(guān)閉JVM才會(huì)釋放此區(qū)域所占用的內(nèi)存。

Young Generation Space?新生區(qū)

新生區(qū)是類的誕生、成長(zhǎng)、消亡的區(qū)域,一個(gè)類在這里產(chǎn)生,應(yīng)用,最后被垃圾回收器收集,結(jié)束生命。新生區(qū)又分為兩部分:伊甸區(qū)(Eden space)和幸存者區(qū)(Survivor pace),所有的類都是在伊甸區(qū)被new出來的。幸存區(qū)有兩個(gè):?0區(qū)(Survivor 0 space)和1區(qū)(Survivor 1 space)。當(dāng)伊甸園的空間用完時(shí),程序又需要?jiǎng)?chuàng)建對(duì)象,JVM的垃圾回收器將對(duì)伊甸園區(qū)進(jìn)行垃圾回收,將伊甸園區(qū)中的不再被其他對(duì)象所引用的對(duì)象進(jìn)行銷毀。然后將伊甸園中的剩余對(duì)象移動(dòng)到幸存0區(qū)。若幸存0區(qū)也滿了,再對(duì)該區(qū)進(jìn)行垃圾回收,然后移動(dòng)到1區(qū)。那如果1區(qū)也滿了呢?再移動(dòng)到養(yǎng)老區(qū)。

Tenure generation space養(yǎng)老區(qū)

養(yǎng)老區(qū)用于保存從新生區(qū)篩選出來的JAVA對(duì)象,一般池對(duì)象都在這個(gè)區(qū)域活躍。???三個(gè)區(qū)的示意圖如下:



?q??Method Area?方法區(qū)

方法區(qū)是被所有線程共享,該區(qū)域保存所有字段和方法字節(jié)碼,以及一些特殊方法如構(gòu)造函數(shù),接口代碼也在此定義。

q??PC Register?程序計(jì)數(shù)器

每個(gè)線程都有一個(gè)程序計(jì)數(shù)器,就是一個(gè)指針,指向方法區(qū)中的方法字節(jié)碼,由執(zhí)行引擎讀取下一條指令。

q??Native Method Stack?本地方法棧


來自jameswxx 樵夫后院 的博客

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的慢慢琢磨JVM的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。