雲棲號資訊:【點擊查看更多行業資訊】
在這裏您能夠找到不一樣行業的第一手的上雲資訊,還在等什麼,快來!
java
VM也就是Java虛擬機,它的內存結構這塊知識點。linux
你說它重要吧,編寫代碼基本用不到它;程序員
你說它不重要吧,程序員想要進階又必須對底層有必定的瞭解。數組
最終仍是決定更加深刻地學習下JVM,同時也用本身的理解詳細地說明Java程序是如何運行的。安全
固然本人目前的能力有限,只能說盡己之能學的越多越好。oracle
1、Java程序開發三步驟工具
編寫、編譯和運行,圖解以下:post
①編寫階段學習
後綴名爲.Java的文件,也就是所謂的源碼。開發工具
可是Java虛擬機它並不認識.Java文件,Java虛擬機和Java語言其實並無必然的聯繫。
其實我挺想吐槽的,大家長的這麼像,居然不認識?
那爲什麼不認識呢?
按照我我的的理解,咱們常說的代碼、Java語言,其實本質上仍是人類定義的一門語言,主要由英文組成,Java虛擬機 自己並不認識它。
因此須要將其編譯成Java虛擬機 認識的語言,即.class文件。
②編譯階段
後綴名爲.class的文件,也就是所謂的字節碼文件。
字節碼文件,就能夠理解成咱們寫代碼一個類(接口、枚舉、註釋)裏面的全部數據。
.class文件是如何來的?
javac編譯器編譯而來的,它能將.java文件編譯成.class文件,這樣的話JVM也就能認識.class文件了。
咱們平時寫的代碼其實也是Java源碼,只不過開發工具很強大,將這三個階段糅合在一塊兒了,以IDEA工具爲例:
src,其實就是源碼的意思,咱們平時編寫的類、接口、枚舉、註解等文件,其實本質上就是.java文件。
利用開發工具中的Show in Explorer功能,能夠找到計算機裏對應的文件夾文件。
out,這個我還不太懂具體是什麼意思,可是.class文件就在這個文件夾裏面。
若是不用開發工具,咱們須要用javac編譯器將.java文件編譯成.class文件;
開發工具等因而自動幫咱們編譯了,很是的方便,可是原理咱們要明白。
既然講到了.class文件,再回顧下反射中剛學的Class對象:
Class自己也是Java裏的一個類,它其實就是指的字節碼文件。
注意:小寫字母開頭的class是Java裏的一個關鍵字,建立一個類時類名前面都會由它來修飾。
因此Class類也就表示成:class Class{};
前面是關鍵字,後面是類名。
最後用一個例子來講明:
咱們在開發工具裏面編寫一個Student類;
那麼在對應的文件夾下就會有一個Student.java文件,也就是源碼;同時開發工具會給我編譯一個對應的Student.class文件,也就是字節碼文件;
而這個字節碼文件會有惟一的一個Class對象,專門用來描述該字節碼文件,在反射中能夠拿來使用,除此以外還能夠做爲線程鎖。
③運行階段
Java虛擬機是認識.class文件的,也就是說可以用來運行程序了。
但它具體是如何運行的呢?
就須要知道JDK了,圖解以下:
①JRE:Java Runtime Environment
翻譯過來就是Java運行環境,包含JVM和運行時所須要的核心類庫。
也就是說有了JRE就能夠運行Java程序了,可是隻能用來運行,若是出了bug,是無法修改的,因此須要JDK。
②JDK:Java Development Kit
翻譯過來就是Java程序開發工具包,包含JRE 和開發人員使用的工具。
前面提到的javac編譯器就是Java工具,JRE中是沒有javac編譯器的,因此它無法修改程序,畢竟沒有編譯的話JVM是不認識的。
Java虛擬機是認識字節碼文件的,而且本質上它就是一個字節碼翻譯器。
它能夠將字節碼文件翻譯成各個系統(Windows系統、Mac系統、linux系統)對應的機器碼;
這樣的話就能確保字節碼文件能在各個系統上正確運行。
這也就是Java所謂的跨平臺特性的由來。
接下來咱們就詳細地瞭解下Java虛擬機。
2、JVM內存結構
咱們看oracle最新的官方文檔,最權威的即是這個官方文檔,畢竟技術是不斷更新的:
JVM內存主要分爲這五大塊:
- 程序計數器(The pc Register)
- Java虛擬機棧(Stacks)
- 堆內存(Heap)
- 方法區(Method Area)
- 本地方法棧(Native Method Stacks)
其中官方文檔中還有一個運行時常量池,暫且不考慮。
①stack棧
咱們常說的棧內存,其實嚴格上來講應該叫Java虛擬機棧。
利用開發工具IDEA斷點調試,咱們能夠很清晰地看到方法進棧出棧的過程。
這是一段很是簡易的代碼:main方法裏面調用method1方法,method1方法裏面調用method2方法。
利用右上角兩個功能鍵,能夠一步一步瞭解方法進棧出棧的過程。
Frames,翻譯過來就是幀的意思,一個方法對應一個棧幀。
什麼叫幀?
在影像動畫裏 ,一個鏡頭就是一幀;那麼棧幀就能夠理解成方法進棧的那一刻,就會造成一個棧幀。
每一個方法進棧都會有一個對應的棧幀。
此外、棧是先進先出原則,mian方法在最底下,最早進來,最後出去。
這個過程能夠用斷點調試模擬出來,感興趣的小夥伴能夠去嘗試下。
其中方法棧裏的線程是不共享的,什麼意思呢?
最直接地理解就是:棧裏面,不一樣的線程是獨立存在的,因此線程安全。
與之相對的是堆、方法區線程是共享的,這又是什麼意思呢?
最直接地理解就是:堆、方法區裏面的數據,不一樣的線程均可以拿過去用,因此線程不安全。
②heep:堆
咱們看oracle最新的官方文檔對其的說明,最權威的即是這個官方文檔,畢竟技術是不斷更新的:
這是翻譯成中文後的頁面,原文都是英文,英語好的小夥伴能夠直接看,不過翻譯大致上也還算是準確的:
- 堆的線程是共享的(數據共享)
- 堆的區域是用來存放對象和數組的(new 對象 new 數組,看到new這個關鍵字就能夠想到堆)
- 堆在Java虛擬機啓動時建立。
- 堆的大小能夠是固定的,也能夠擴展:使用「-Xms」與「-Xmx」控制堆的最小與最大內存。
此外對象是會建立不少的,其中一小部分會一直被使用到,大部分咱們使用後就會捨棄,因此這也是垃圾收集器管理的主要區域。
根據這兩種不一樣的狀況,垃圾收集器爲了更好地一一應對,堆內存又被劃分紅新生代和老年代:
- 老年代:對象會一直被使用到,不會輕易地被回收
- 新生代:對象朝生夕滅,須要常常回收
其中還有更加詳細地細分,實在是有點學不動了,暫時不考慮。
③方法區
一樣的,看官方文檔:
這個翻譯有點問題,但大致上也能看:
- 方法區的線程是共享的。
- 方法區在Java虛擬機啓動時建立。
- 方法區的做用是存儲每一個類的結構。
既然是存儲類的結構,那麼.class文件也就是存儲在這個內存區域。
說白了就是類裏面的數據,都是存在這個方法區裏面的。
類中有什麼?
成員變量,成員方法等等,其中方法和變量還分靜態和非靜態。
這些都是存儲在方法區裏面的,除了類裏的數據,常量池也在方法區裏面。
方法運行時,會從方法區進入到棧裏面;
建立該類的對象時,會將建立的對象存放在堆裏面。
其中靜態變量隨着類的加載而加載,它並不會進堆。
以上三塊即是和咱們編寫Java代碼息息相關的內存區域,除此以外還有兩塊區域:
④程序計數器
咱們平時編寫的代碼能夠被反編譯成JVM指令,cpu就是依靠這個程序計數器執行指令的:
程序計數器會保存當前執行指令的地址,好比說程序計數器如今保存的爲0,那麼CPU會執行0對應的指令;
一旦指令執行,程序計數器將更新到下一條指令,上圖中也就是3,CPU接着會執行3對應的指令。
就這樣依次執行下去,程序計數器的做用就在於保證程序能正常運行。
⑤本地方法棧
①中的棧準確地說應該叫虛擬機棧,它服務的方法是Java方法;
本地方法棧做用和其是差很少的,不一樣的地方在於它服務的方法不是Java方法而是本地方法;
什麼叫本地方法?咱們其實見過,以下圖:
Objcet類中就有本地方法,被native這個關鍵字修飾,native就是本地的意思,這很好記憶。
也就是說該方法不是由Java語言寫的,而是由本地語言寫的,好比說C語言。
固然虛擬機規範中並未給出強制規定由什麼本地語言寫,不一樣的虛擬機能夠自由實現。
以上即是對JVM內存結的說明,除了JVM內存結構外,還有兩大塊……
3、JVM體系結構
源碼經過編譯成字節碼文件,再被類加載器加載進內存,最後通過各類交互被執行,大體就是這麼一個運行流程:
①類加載子系統(Class loader SubSystem)
它的做用是將類加載進內存,在Java中對應一個類ClassLoader,該類是一個抽象類。
- 引導類加載器(Bootstrap ClassLoader)
它是由C++編寫的,是用來引導Java程序的,它並非ClassLoader子類。
- 擴展類加載器(Extension ClassLoader)
它是由Java程序編寫的,負責加載java平臺中擴展功能的一些jar包。
- 應用類加載器:(Application ClassLoader)
它是由Java程序編寫的,加載編寫的代碼。
②運行時數據區(Runtime Data Areas)
也就是JVM內存結構,上述已經詳細講解了,這也是對於程序員來講須要去重點了解的。
③執行引擎(Execution Engine)
解釋器interpreter:它是用於讀取字節碼文件,對其解釋並逐一執行,它的解釋速度較快,可是執行較慢,而且它有一個致命的缺點,就是當同一個方法被屢次調用時,它每次都要解釋。
即時編譯器JIT Compiler:它是用來優化解釋器的,解決上述的缺點。
垃圾回收器GC:收集並回收由new關鍵字建立的對象。
④本地方法接口和本地方法庫
存放本地方法。
總結:
以上即是對Java程序運行的詳解,以及對JVM內存的分析。
奈何本人能力實在是有限,還有一些地方法沒有弄明白,講解的也不算很深刻,但就我當前具有的能力而言,已經算是最詳細的解讀了。
【雲棲號在線課堂】天天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/live當即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK
原文發佈時間:2020-06-06
本文做者:劉小愛
本文來自:「掘金」,瞭解相關信息能夠關注「掘金」