前言:
本篇以.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函式繼續執行。關於這一點可以參照以前的文章:點選檢視原理
結尾:
作者:江湖評談
關注我,帶你瞭解高價值和好玩的技術