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

江湖評談發表於2023-03-02

前言:

本篇以.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

相關文章