最近在學jvm,浮于表面的學了之后,發現jvm并沒有我想象中的那么神秘,這篇文章將會用接地氣的方式來說一說這些jvm的相關概念以及名詞解釋。
帶著下面兩個問題來閱讀
- 認識了解JVM大致有什么
- 在代碼運行時的都在背后做了什么
JVM是個啥?
拋開專業語句來說,你可以把jvm理解成一個小的電腦,運行在Linux或者windows等這樣的操作系統,他直接和操作系統進行接觸,不會直接操作底層的硬件,操作系統來幫我們完成與硬件的交互
Java文件從編寫到運行,JVM內部都發生了什么?
比如我們現在寫了一個 HelloWorld.java 好了,那這個 HelloWorld.java 拋開所有東西不談,那是不是就類似于一個文本文件,只是這個文本文件它寫的都是英文,而且有一定的縮進而已。
那我們的 JVM 是不認識文本文件的,所以它需要編譯,讓其成為一個它會讀二進制文件的 HelloWorld.class,也就是字節碼文件
①類加載器
如果JVM想要加載這個.class文件,就要通過類加載器這個搬運工,會把所有的.class文件都搬運進JVM里面來
②方法區
是用于存放類似于元數據信息方面的數據的,比如類信息,常量,靜態變量,編譯后代碼···等
類加載器將 .class 文件搬過來就是先丟到這一塊上
③堆
堆主要存放了一些存儲的數據,比如對象實例,數組等,幾乎所有的java對象都是分配在堆上面的,一小部分是分配在棧中的(極小部分),他和方法區都屬于線程共享區域,也就是說他們都是線程不安全的
④棧
棧是我們代碼運行的空間。我們編寫的每一個方法都會放到棧中去運行,當一個方法進入棧時,就會有一個棧幀被壓入棧中,當方法執行結束后,這個方法的棧幀就會被彈出,主打一個先進后出,后進先出
⑤程序計數器
主要就是完成一個加載工作,類似一個指針一樣的,指向下一個要執行的字節碼命令的地址。和棧一樣,是線程獨享的,就是說線程中都會有對應的每一個區域而不會存在并發和多線程的問題。
小總結
Java文件經過編譯后變成 .class 字節碼文件
字節碼文件通過類加載器被搬運到 JVM 虛擬機中
虛擬機主要的5大塊:方法區,堆都為線程共享區域,有線程安全問題,棧和本地方法棧和計數器都是獨享區域,不存在線程安全問題,而 JVM 的調優主要就是圍繞堆,棧兩大塊進行
例子
我們通過一個主函數調用一個類,來簡要的說明這一整個過程都發生了什么。
這是一個簡單的Student類
一個Main方法
1.編譯好App.Java文件獲得App.class文件后,執行App.class文件,系統會啟動一個JVM進程,JVM進程會從classpath路徑下找到一個名為APP.class的二進制文件,然后用類加載器,將這個二進制文件加載到運行時數據區中的方法區內,這個過程叫做App類的加載
2.JVM找到App的程序入口,執行main方法
3.這個main的第一條語句是new一個Student對象出來,那么這個時候JVM就會趕緊去方法去看看有沒有這個類的信息,所以JVM立即加載Student類,把這個類的信息放到方法區中去
4.加載完Student之后,JVM會在堆中為這個對象分配一個內存,然后調用構造函數初始化對象,這個Student對象實例會將指向方法區中Student類的類型信息的引用寫入自己的方法頭中去
5.執行student.sayName()時,JVM會根據student的引用找到student實例,再根據student對象持有的引用定位到方法區中Student類型信息的方法表中找到對應的方法,或者這個.sayName()的字節碼地址
6.執行sayName()
其實也不用管太多,只需要知道對象實例初始化時會去方法區中找類信息,完成后再到棧那里去運行方法。找方法就在方法表中找。
這就是JVM的第一部分啦,認識了解JVM大致有什么,在代碼運行時的都在背后做了什么,下一節再講講這個類加載器,碼字不易點一個贊吧