1. 初識JVM
問題:我們的.java 文件是怎么運行的摩瞎?
解答:我們的.java 文件通過編譯器編譯成.class 文件 毫别,通過我們的ClassLoader 加載器加載到JVM運行時內(nèi)存塊。然后我們的CPU 去運行我們的程序。運行我們的程序是需要計算機里的很多模塊配合的儿普,如CPU ,內(nèi)存掷倔,寄存器 等眉孩。所以,不管是什么語言編寫的程序,只要最終編譯成.class 文件浪汪,那我們的java 虛擬機 就可以運行他巴柿,只要安裝了java 虛擬機,就可以在任何平臺上跑java 的程序死遭,這也是java 強大的原因广恢。以前塞班系統(tǒng)上的應(yīng)用程序就是用我們的java 寫的。
問題:那我們的程序在虛擬機中又是怎么運行的呢殃姓?
解答:java虛擬機 也相當(dāng)于我們的一個平臺袁波,一個宿主。每一個應(yīng)用在java 虛擬機中都是一個獨立的門戶蜗侈。當(dāng)我們的應(yīng)用需要到的程序文件時就會通過我們的ClassLoader 把.class 文件加載到JVM運行時內(nèi)存中篷牌。ClassLoader 怎么加載的我們后續(xù)再解釋。JVM 運行時內(nèi)存大致可以分為五大類:方法區(qū)踏幻,堆區(qū)枷颊,虛擬機棧,本地方法棧该面,程序計數(shù)器夭苗。然而 我們的應(yīng)用不可能都是一個線程,可能是多個線程隔缀。根據(jù)線程資源分配的話分為:線程共享區(qū)(方法區(qū)题造,堆區(qū)) 線程私有區(qū)(虛擬機棧,本地方法棧猾瘸,程序計數(shù)器)界赔。
現(xiàn)在我們分別來介紹一下這5個部分到底有什么作用,我們的程序在這5個功能模塊上是怎么協(xié)調(diào)運行我們的程序的牵触。
- 程序計數(shù)器:從字面上的意思可理解成 運行程序的一個標(biāo)記的東西淮悼。 我們的java程序是多線程的,CPU 可以在多個線程中分配時間片揽思。當(dāng)我們的某一個線程被掛起時袜腥,我們的程序計數(shù)器就要記錄當(dāng)前代碼執(zhí)行到了那一行,下一次線程被喚醒時钉汗,程序繼續(xù)從之前運行的那里開始運行羹令。程序計數(shù)器的生命周期和線程是同步的。
- 虛擬機棧:說到棧损痰,那就很明顯就是先進后出的特恬。當(dāng)我們運行某一個方法時就會創(chuàng)建一個棧幀,我們運行的方法 會在這個棧幀中去操作徐钠。棧幀中包括局部變量表,操作數(shù)棧役首,動態(tài)連接尝丐,返回地址等显拜。正常我們的程序會編譯成字節(jié)碼指令,會在操作棧中入棧出棧 計算出每個方法的運行結(jié)果爹袁,然后返回远荠,退出方法圃泡。
- 本地方法棧:本地方法棧和虛擬機棧大致相同动遭,主要就是執(zhí)行本地方法 native 方法绽慈。JNI開發(fā)過程中會用到本地方法棧昆箕。
- 堆:JVM 運行時內(nèi)存管理的最大的一塊內(nèi)存领迈,該區(qū)域是存放我們對象實例具被,所以這塊的內(nèi)存回收和創(chuàng)建 都是非常重要的奔誓,內(nèi)存是有限的琢锋,如果管理不當(dāng)就會導(dǎo)致內(nèi)存不夠用绎秒,不夠用就會出現(xiàn)OOM 浦妄。
- 方法區(qū):方法區(qū)主要存儲一些 加載的類的信息 版本號,字段见芹,方法剂娄,接口 ,常量玄呛,靜態(tài)變量阅懦。