作為一名Java程序員,我們需要知道Java代碼是怎么運(yùn)行的。最近復(fù)習(xí)了深入理解Java虛擬機(jī)這本書(shū),做了一下筆記,希望對(duì)大家有幫助,如果有不正確的地方,歡迎提出,感激不盡。
創(chuàng)新互聯(lián)專(zhuān)注為客戶(hù)提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于做網(wǎng)站、網(wǎng)站設(shè)計(jì)、靖邊網(wǎng)絡(luò)推廣、微信小程序定制開(kāi)發(fā)、靖邊網(wǎng)絡(luò)營(yíng)銷(xiāo)、靖邊企業(yè)策劃、靖邊品牌公關(guān)、搜索引擎seo、人物專(zhuān)訪(fǎng)、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供靖邊建站搭建服務(wù),24小時(shí)服務(wù)熱線(xiàn):18982081108,官方網(wǎng)址:www.cdcxhl.com
在這里小編建了一個(gè)前端學(xué)習(xí)交流扣扣群:132667127,我自己整理的最新的前端資料和高級(jí)開(kāi)發(fā)教程,如果有想需要的,可以加群一起學(xué)習(xí)交流
java 代碼運(yùn)行主要流程
本文主要講解流程如下:
編譯
我們都知道,java代碼是運(yùn)行在Java虛擬機(jī)上的。但是java是一門(mén)面向?qū)ο蟮母呒?jí)語(yǔ)言,它不僅語(yǔ)法非常復(fù)雜,抽象程度也非常高,并不能直接運(yùn)行在計(jì)算機(jī)硬件機(jī)器上。
Java虛擬機(jī)(Java Virtual Machine 簡(jiǎn)稱(chēng)JVM)是運(yùn)行所有Java程序的抽象計(jì)算機(jī),是Java語(yǔ)言的運(yùn)行環(huán)境。
因此,在運(yùn)行Java程序之前,需要編譯器把代碼編譯成java虛擬機(jī)所能識(shí)別的指令程序,這就是Java字節(jié)碼,即class文件。
所以,Java代碼運(yùn)行的第一步是:把Java源代碼編譯成.class 字節(jié)碼文件。
類(lèi)加載
在Class文件中描述的各種信息,需要被加載到虛擬機(jī)之后才能運(yùn)行和使用。因此,需要把class字節(jié)碼文件加載到Java虛擬機(jī)來(lái)。
虛擬機(jī)把描述類(lèi)的數(shù)據(jù)從 Class 文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直接使用的 Java 類(lèi)型,這就是虛擬機(jī)的 類(lèi)加載機(jī)制。
加載
在 加載階段,虛擬機(jī)需要完成以下3件事情:
加載階段完成后,這些二進(jìn)制字節(jié)流按照虛擬機(jī)所需的格式存儲(chǔ)在 方法區(qū)之中。
驗(yàn)證
為了確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,不會(huì)危害虛擬機(jī)的安全,Java虛擬機(jī)對(duì)輸入的字節(jié)流走 驗(yàn)證過(guò)程。
驗(yàn)證階段包括四個(gè)階段:文件格式驗(yàn)證、元數(shù)據(jù)驗(yàn)證、字節(jié)碼驗(yàn)證、符號(hào)引用驗(yàn)證。
準(zhǔn)備
準(zhǔn)備階段是正式為類(lèi)變量分配內(nèi)存并設(shè)置類(lèi)變量初始值,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。如:
public static int value =123;
變量value在準(zhǔn)備階段過(guò)后的初始值是0而不是123。
解析
解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程。
比如:com.User類(lèi)引用com.Tool類(lèi),在編譯時(shí),User類(lèi)不知道Tool類(lèi)的實(shí)際內(nèi)存地址,因此只能使用符號(hào)com.Tool(假設(shè))來(lái)表示。而在類(lèi)加載加載User類(lèi)的時(shí)候,可以通過(guò)虛擬機(jī)獲取Tool類(lèi)的實(shí)際內(nèi)存地址,因此便可以將符號(hào)com.Tool替換為T(mén)ool類(lèi)的實(shí)際內(nèi)存地址,即直接引用地址。
解析動(dòng)作主要針對(duì)類(lèi)或接口、字段、類(lèi)方法、接口方法、方法類(lèi)型、方法句柄和調(diào)用點(diǎn)限定符 7 類(lèi)符號(hào)引用進(jìn)行。
初始化
到了初始化階段,才真正開(kāi)始執(zhí)行類(lèi)中定義的Java字節(jié)碼。在這個(gè)階段,則根據(jù)程序員通過(guò)程序制定的主觀計(jì)劃去初始化類(lèi)變量和其他資源。
創(chuàng)建對(duì)象
Java虛擬機(jī)是如何執(zhí)行字節(jié)碼的呢?我們先來(lái)看一下運(yùn)行時(shí)創(chuàng)建對(duì)象。
Java是面向?qū)ο蟮木幊陶Z(yǔ)言,程序的運(yùn)行是以對(duì)象為調(diào)用單位的。
方法調(diào)用
JVM的調(diào)用單位是對(duì)象,但是真正執(zhí)行功能性的代碼還是對(duì)象上的方法。
在運(yùn)行過(guò)程中,每當(dāng)調(diào)用進(jìn)入一個(gè)java方法,java虛擬機(jī)會(huì)在當(dāng)前線(xiàn)程的java方法棧中生成一個(gè)棧幀,用以存放局部變量以及字節(jié)碼的操作數(shù)。方法棧內(nèi)存是線(xiàn)程私有的,每個(gè)線(xiàn)程都有自己的方法棧。如果對(duì)應(yīng)的方法是本地方法,則對(duì)應(yīng)的就是本地方法棧。
java運(yùn)行時(shí)數(shù)據(jù)區(qū)域如下:
解釋
當(dāng)調(diào)用Java對(duì)象的某個(gè)方法時(shí),JVM執(zhí)行引擎會(huì)將該方法的字節(jié)碼文件翻譯成計(jì)算機(jī)所能識(shí)別的機(jī)器碼,機(jī)器碼信息保存在方法區(qū)中。翻譯有解釋執(zhí)行和即時(shí)編譯兩種方式。
兩種翻譯方式的區(qū)別如下:
解釋執(zhí)行來(lái)一行代碼,解釋一行,大部分不常用的代碼,都是采用這種方式。
即使編譯
對(duì)于部分熱點(diǎn)代碼,將一個(gè)方法包含的所有字節(jié)碼翻譯成機(jī)器指令,以提高java虛擬機(jī)的運(yùn)行效率。
即時(shí)編譯是建立經(jīng)典的 二八定律上,即20%代碼占據(jù)了80%的計(jì)算資源。
執(zhí)行指令
多線(xiàn)程上下文切換
CPU一通上電,就會(huì)周而復(fù)始從內(nèi)存中獲取指令、譯碼、執(zhí)行。