如何阅读JVM 源码
JDK中JVM(安装在本地C:\Program Files\Java\jdk1.8.0_121\jre\bin\server下jvm.dll)本身并不开源,只能找来openJDK来看(说是和JDK相似度很高)
openjdk —— corba:不流行的多语言、分布式通讯接口 —— hotspot:Java 虚拟机 —— jaxp:XML 处理 —— jaxws:一组 XML web services 的 Java API —— jdk:java 开发工具包 —— —— 针对操作系统的部分 —— —— share:与平台无关的实现 —— langtools:Java 语言工具 —— nashorn:JVM 上的 JavaScript 运行时
hotspot 代码结构
├─agent Serviceability Agent的实现 ├─make 用来build出HotSpot的各种配置文件 ├─src HotSpot VM的源代码 │ ├─cpu CPU相关代码 │ ├─os 操作系统相关代码 │ ├─os_cpu 操作系统+CPU的组合相关的代码 │ └─share 平台无关的共通代码 │ ├─tools 工具 │ │ ├─hsdis 反汇编插件 │ │ ├─IdealGraphVisualizer 将server编译器的中间代码可视化的工具 │ │ ├─launcher 启动程序“java” │ │ ├─LogCompilation 将-XX:+LogCompilation输出的日志(hotspot.log)整理成更容易阅读的格式的工具 │ │ └─ProjectCreator 生成Visual Studio的project文件的工具 │ └─vm HotSpot VM的核心代码 │ ├─adlc 平台描述文件(上面的cpu或os_cpu里的*.ad文件)的编译器 │ ├─asm 汇编器接口 │ ├─c1 client编译器 │ ├─ci 动态编译器的公共服务/接口 │ ├─classfile 类文件的处理(包括类加载和系统符号表等) │ ├─code 动态生成的代码的管理 │ ├─compiler 编译器接口 │ ├─gc_implementation GC的实现 │ │ ├─concurrentMarkSweep Concurrent Mark Sweep GC的实现 │ │ ├─g1 Garbage-First GC的实现(不使用老的分代GC框架) │ │ ├─parallelScavenge ParallelScavenge GC的实现(server VM默认,不使用老的分代式GC框架) │ │ ├─parNew ParNew GC的实现 │ │ └─shared GC的共同实现 │ ├─gc_interface GC的接口 │ ├─interpreter 解释器,包括“模板解释器”(官方版在用)和“C++解释器”(官方版不在用) │ ├─libadt 一些抽象数据结构 │ ├─memory 内存管理相关(老的分代GC框架也在这里) │ ├─oops HotSpot VM的对象系统的实现 │ ├─opto server编译器 │ ├─prims HotSpot VM的对外接口,包括部分标准库的native部分和JVMTI实现 │ ├─runtime 运行时支持库(包括线程管理、编译器调度、锁、反射等) │ ├─services 主要是用来支持JMX之类的管理功能的接口 │ ├─shark 基于LLVM的JIT编译器(官方版里没有使用) │ └─utilities 一些基本的工具类 └─test 单元测试
举个例子,看下wait 在 JVM 中的实现:jdk\src\share\native\java\lang\Object.c
#include <stdio.h> #include <signal.h> #include <limits.h> #include "jni.h" #include "jni_util.h" #include "jvm.h" #include "java_lang_Object.h" static JNINativeMethod methods[] = { {"hashCode", "()I", (void *)&JVM_IHashCode}, {"wait", "(J)V", (void *)&JVM_MonitorWait}, {"notify", "()V", (void *)&JVM_MonitorNotify}, {"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll}, {"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone}, }; JNIEXPORT void JNICALL Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls) { (*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])); } JNIEXPORT jclass JNICALL Java_java_lang_Object_getClass(JNIEnv *env, jobject this) { if (this == NULL) { JNU_ThrowNullPointerException(env, NULL); return 0; } else { return (*env)->GetObjectClass(env, this); } }
openjdk-8-src-b132-03_mar_2014.zip\openjdk\hotspot\src\share\vm\runtime\objectMonitor.cpp
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { Thread * const Self = THREAD ; assert(Self->is_Java_thread(), "Must be Java thread!"); JavaThread *jt = (JavaThread *)THREAD; DeferredInitialize () ; // Throw IMSX or IEX. CHECK_OWNER(); EventJavaMonitorWait event; // check for a pending interrupt if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) { // post monitor waited event. Note that this is past-tense, we are done waiting. if (JvmtiExport::should_post_monitor_waited()) { // Note: 'false' parameter is passed here because the // wait was not timed out due to thread interrupt. JvmtiExport::post_monitor_waited(jt, this, false); } if (event.should_commit()) { post_monitor_wait_event(&event, 0, millis, false); } TEVENT (Wait - Throw IEX) ; THROW(vmSymbols::java_lang_InterruptedException()); return ; } TEVENT (Wait) ; assert (Self->_Stalled == 0, "invariant") ; Self->_Stalled = intptr_t(this) ; jt->set_current_waiting_monitor(this); // create a node to be put into the queue // Critically, after we reset() the event but prior to park(), we must check // for a pending interrupt. ObjectWaiter node(Self);//Self 是Thread 对象,将当前线程封装成ObjectWaiter对象node node.TState = ObjectWaiter::TS_WAIT ; Self->_ParkEvent->reset() ; OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag // Enter the waiting queue, which is a circular doubly linked list in this case // but it could be a priority queue or any data structure. // _WaitSetLock protects the wait queue. Normally the wait queue is accessed only // by the the owner of the monitor *except* in the case where park() // returns because of a timeout of interrupt. Contention is exceptionally rare // so we use a simple spin-lock instead of a heavier-weight blocking lock. Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ; AddWaiter (&node) ; //将 node加入到 ObjectWaiter 的_WaitSet 中 Thread::SpinRelease (&_WaitSetLock) ; if ((SyncFlags & 4) == 0) { _Responsible = NULL ; } intptr_t save = _recursions; // record the old recursion count _waiters++; // increment the number of waiters _recursions = 0; // set the recursion level to be 1 exit (true, Self) ; // exit the monitor guarantee (_owner != Self, "invariant") ; // As soon as the ObjectMonitor's ownership is dropped in the exit() // call above, another thread can enter() the ObjectMonitor, do the // notify(), and exit() the ObjectMonitor. If the other thread's // exit() call chooses this thread as the successor and the unpark() // call happens to occur while this thread is posting a // MONITOR_CONTENDED_EXIT event, then we run the risk of the event // handler using RawMonitors and consuming the unpark(). // // To avoid the problem, we re-post the event. This does no harm // even if the original unpark() was not consumed because we are the // chosen successor for this monitor. if (node._notified != 0 && _succ == Self) { node._event->unpark(); } // The thread is on the WaitSet list - now park() it. // On MP systems it's conceivable that a brief spin before we park // could be profitable. // // TODO-FIXME: change the following logic to a loop of the form // while (!timeout && !interrupted && _notified == 0) park() int ret = OS_OK ; int WasNotified = 0 ; { // State transition wrappers OSThread* osthread = Self->osthread(); OSThreadWaitState osts(osthread, true); { ThreadBlockInVM tbivm(jt); // Thread is in thread_blocked state and oop access is unsafe. jt->set_suspend_equivalent(); if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) { // Intentionally empty } else if (node._notified == 0) { if (millis <= 0) { Self->_ParkEvent->park () ; //重点分析这句 } else { ret = Self->_ParkEvent->park (millis) ; //重点分析这句 } } // were we externally suspended while we were waiting? if (ExitSuspendEquivalent (jt)) { // TODO-FIXME: add -- if succ == Self then succ = null. jt->java_suspend_self(); } } // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm // Node may be on the WaitSet, the EntryList (or cxq), or in transition // from the WaitSet to the EntryList. // See if we need to remove Node from the WaitSet. // We use double-checked locking to avoid grabbing _WaitSetLock // if the thread is not on the wait queue. // // Note that we don't need a fence before the fetch of TState. // In the worst case we'll fetch a old-stale value of TS_WAIT previously // written by the is thread. (perhaps the fetch might even be satisfied // by a look-aside into the processor's own store buffer, although given // the length of the code path between the prior ST and this load that's // highly unlikely). If the following LD fetches a stale TS_WAIT value // then we'll acquire the lock and then re-fetch a fresh TState value. // That is, we fail toward safety. if (node.TState == ObjectWaiter::TS_WAIT) { Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ; if (node.TState == ObjectWaiter::TS_WAIT) { DequeueSpecificWaiter (&node) ; // unlink from WaitSet assert(node._notified == 0, "invariant"); node.TState = ObjectWaiter::TS_RUN ; } Thread::SpinRelease (&_WaitSetLock) ; } // The thread is now either on off-list (TS_RUN), // on the EntryList (TS_ENTER), or on the cxq (TS_CXQ). // The Node's TState variable is stable from the perspective of this thread. // No other threads will asynchronously modify TState. guarantee (node.TState != ObjectWaiter::TS_WAIT, "invariant") ; OrderAccess::loadload() ; if (_succ == Self) _succ = NULL ; WasNotified = node._notified ; // Reentry phase -- reacquire the monitor. // re-enter contended monitor after object.wait(). // retain OBJECT_WAIT state until re-enter successfully completes // Thread state is thread_in_vm and oop access is again safe, // although the raw address of the object may have changed. // (Don't cache naked oops over safepoints, of course). // post monitor waited event. Note that this is past-tense, we are done waiting. if (JvmtiExport::should_post_monitor_waited()) { JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT); } if (event.should_commit()) { post_monitor_wait_event(&event, node._notifier_tid, millis, ret == OS_TIMEOUT); } OrderAccess::fence() ; assert (Self->_Stalled != 0, "invariant") ; Self->_Stalled = 0 ; assert (_owner != Self, "invariant") ; ObjectWaiter::TStates v = node.TState ; if (v == ObjectWaiter::TS_RUN) { enter (Self) ; } else { guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ; ReenterI (Self, &node) ; node.wait_reenter_end(this); } // Self has reacquired the lock. // Lifecycle - the node representing Self must not appear on any queues. // Node is about to go out-of-scope, but even if it were immortal we wouldn't // want residual elements associated with this thread left on any lists. guarantee (node.TState == ObjectWaiter::TS_RUN, "invariant") ; assert (_owner == Self, "invariant") ; assert (_succ != Self , "invariant") ; } // OSThreadWaitState() jt->set_current_waiting_monitor(NULL); guarantee (_recursions == 0, "invariant") ; _recursions = save; // restore the old recursion count _waiters--; // decrement the number of waiters // Verify a few postconditions assert (_owner == Self , "invariant") ; assert (_succ != Self , "invariant") ; assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ; if (SyncFlags & 32) { OrderAccess::fence() ; } // check if the notification happened if (!WasNotified) { // no, it could be timeout or Thread.interrupt() or both // check for interrupt event, otherwise it is timeout if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) { TEVENT (Wait - throw IEX from epilog) ; THROW(vmSymbols::java_lang_InterruptedException()); } } // NOTE: Spurious wake up will be consider as timeout. // Monitor notify has precedence over thread interrupt. }
- ObjectWaiter node(Self); Self 是Thread 对象,将当前线程封装成ObjectWaiter对象node;
- ObjectMonitor::AddWaiter() 将 node加入到 ObjectWaiter 的_WaitSet 中;
- exit (true, Self) ; // exit the monitor 线程退出monitor;
- Self->_ParkEvent->park () ; 最终底层的park方法挂起线程;
参考资料:
- openjdk-8-src-b132-03_mar_2014.zip\openjdk\hotspot\src\os\windows\vm
- https://blog.csdn.net/qq_26222859/article/details/53930941
- https://www.jianshu.com/p/b91258bc08ac
- http://hg.openjdk.java.net/jdk7u/jdk7u/hotspot/file/677234770800/src/os/linux/vm/os_linux.cpp