從Object.wat()方法看JNI及native方法底層呼叫邏輯
前言
早上debug join方法的時候,其內部呼叫wait方法,wait是Object中的native方法,但是在ClassLoader類中的findNative中打斷點,不會進去斷點。然後想了一下,是不是因為Object是Bootstrap類載入器載入的原因。
那麼怎麼才能知道native呼叫的到底是什麼方法呢?在網上搜索"Java如何檢視native方法的實現",沒有搜到可用的內容。
索性自己去翻一下hostspot jdk的原始碼,我下載的是openjdk-8u40-src-b25-10_feb_2015.zip,可以從openjdk官網下載。
舉個例子,比如我要搜尋Object中的wait方法:
1、openjdk目錄結構分析(有助於快速定位原始碼位置)
請原諒我眼花繚亂的框選,開啟Object.c看看:
2、初見Object.c
從wait方法入口進去,實現在jvm.cpp中
JDK中用到的jni介面,最終都會在jvm.h檔案中定義,並在jvm.cpp中作為C++實現的入口,也就是說jvm.cpp是Java世界和JVM中C++世界溝通的橋樑。
JVMWrapper("JVM_MonitorWait");這一句是定義了一個巨集
看一下270行,我搜了下Histogram的意思,是直方圖,猜測這裡只是在做JVM統計,或者為了監控而呼叫的邏輯。這裡先略過。
2.1 使用oop指標指向Java物件
接著看這行:
是把當前執行的java類包裝成一個Handle型別,Handle型別,見下圖,將Java物件賦值給了一個oop指標型別。
2.2 緊接著這行:JvmtiExport::should_post_monitor_wait(),553行
should_post_monitor_wait預設false,在jvmtiEventController.cpp中的recompute_enabled方法中會進行設定,搜了下recompute_enabled在jvmtiEventController.cpp有多處呼叫,從名字上看可能有事件驅動的邏輯,should_post_monitor_wait的值應該也是響應時間設定的。
有哪些事件?導致wait方法的這個should_post_monitor_wait變數變化的是哪些事件?
在Java中通過JNI介面可以實現Java呼叫本地方法;通過JVMTI介面可以實現在C++空間呼叫Java物件的方法。
jvmtiEventController.cpp中的recompute_enabled的部分方法體:
再看JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);這行。
小結:
寫的好亂,很多細節沒怎麼懂,看了if語句塊中的註釋,這段的意思是:當前執行緒已經擁有監視器,但是沒被加到等待佇列中,JVMTI_EVENT_MONITOR_WAIT事件沒辦法處理unpark(),意思應該就是沒辦法釋放鎖。
那post_monitor_wait這個意思應該就是推遲監視器的等待,就是先不釋放鎖。
2.3 接著看ObjectSynchronizer::wait(obj, ms, CHECK);
這個呼叫的實現在synchronizer.cpp檔案中,
1)首先,如果UseBiasedLocking為true,使用偏向鎖
2)如果millis < 0,丟擲異常
3)inflate()中是鎖膨脹升級邏輯
4)呼叫objectMonitor.cpp中的wait方法。wait的大部分邏輯在這裡。可以參見延伸閱讀[1]
總結:
本文通過介紹openjdk底層原始碼的目錄結構,wait方法執行涉及到的呼叫關係。對從Java方法呼叫到C++程式碼呼叫有一個感性的認識。具體C++程式碼邏輯,還需要進一步分析。
延伸閱讀:
[1] JVM原始碼分析之Object.wait/notify實現
[2] 併發程式設計的藝術
關於搜尋技巧:
文章開頭提到,在網上搜索"Java如何檢視native方法的實現",沒有搜到可用的內容。然後在看原始碼的過程中,看到C++程式碼裡的這個方法JVMWrapper。不是很明白,就去搜狗微信上搜索了JVMWrapper。
搜尋到了原始碼分析:Java中的Thread的建立和執行 這篇文章。