Java/.Net雙平臺核心,Jvm和CLR運行異同點

前言:

本篇以.Net 7.0.2 CLR 和 OpenJDk19參照,解析下它們各自調用函數的異同。
以下爲個人理解。


概述

JDK大約5.9G,CLR大約7.6G,兩者相差1.7G左右。

root@tang-virtual-machine:/home/tang# cd jdk-jdk-19-36
root@tang-virtual-machine:/home/tang/jdk-jdk-19-36# du -sh
5.9G	.
root@tang-virtual-machine:/home/tang/Downloads# du -sh
7.6G	.

JVM事先把需要運行的函數編譯好存放在某個地址,此後通過呼叫樁(call_stub)進行調用,這裏的某個地址裏面包含了需要運行的函數頭地址,在裏面跳轉運行。
CLR是一邊運行一邊編譯,遇到哪個函數就編譯哪個,編譯完成後跳轉到此函數的函數頭(pCode)地址進行運行。


具體的呢?先看JVM,它的調用如下

Main-》-》Clone3-》JavaMain-》InitializeJVM-》create_vm-》init_globals-》generate_call_stub() //這裏省略了部分

generate_call_stub函數對需要運行的函數進行編譯,它的代碼實際上是生成機器碼,然後返回函數樁頭

StubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address);
_call_stub_entry

也就是call_stub接受的那個地址。_call_stub_entry裏面包含了需要運行函數的函數頭地址,在call_stub裏面進行地址跳轉調用。此處可以的原理可以看下以前文章:點擊此處查看原理


那麼call_stub的調用是什麼呢?

Main-》-》Clone3-》JavaMain-》InitializeJVM-》create_vm-》initialize_java_lang_classes-》call_stub

可以看到generate_call_stub和call_stub兩者在create_vm函數處分爲兩處,首先調用了generate_call_stub對函數進行了編譯,再調用call_stub對編譯好的函數進行了調用。


再看CLR,以調用託管的Main函數入口爲例。常例,先看下它的調用

Main-》RunMain-》MethodDescCallSite::Call-》MethodDescCallSite::CallTargetWorker-》CallDescrWorkerWithHandler-》CallDescrWorkerInternal-》ThePreStub-》PreStubWorker

如果Main函數裏面調用了其它函數,比如如下:

static void Main(string[] args)
{
   Console.Write("Tian xia feng yun chu wo bei");
}

Main裏面調用了Console.Write函數,當CLR運行到此函數處,又把上面的調用運行了一邊

MethodDescCallSite::Call-》MethodDescCallSite::CallTargetWorker-》CallDescrWorkerWithHandler-》CallDescrWorkerInternal-》ThePreStub-》PreStubWorker

直到Console.Write函數編譯和運行都完畢,才返回Main函數繼續執行。關於這一點可以參照以前的文章:點擊查看原理


結尾:

作者:江湖評談
關注我,帶你瞭解高價值和好玩的技術
image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章