[KANMARS原创] - (六) 从JVM源码来理解JavaThread类启动过程与main方法调用
JavaThread类启动过程与main方法调用
JavaThread对应于每一个java层的Thread,例如调用public static void main(String[] args)时,自动生成一个java线程,而且每new Thread(){()->{}}.start();的时候也会生成一个java线程。
根据一些粗显的知识,java线程中包含虚拟机栈、程序计数器。
虚拟机栈包含:栈帧,每一个方法调用都会生成一个栈帧
栈帧包含: 局部变量表、操作数栈、动态链接、方法返回地址
———————————————————————————————————————————————–
或许大家作为JAVA程序员想象了一遍又一遍的JVM内部实现,但大部分是错误的想法,(例如 :每一个虚拟机栈包含了局部变量表,但在OpenJDK 的JVM中,虚拟机栈和局部变量表是分离的实现) ,今天我们就来看一下,在JVM中,这些东西是怎么实现的。
———————————————————————————————————————————————–
JavaThread是如何启动并运行的
JavaThread的启动位于
java.c:main -> java.c:javaMain -> java.c:InitializeJVM->Thread.cpp:CreateJavaVM
JavaThread内部的重要属性如下:
JavaThread _next; 下一个JavaThread
oop _threadObj;
JavaFrameAnchor _anchor; JavaFrame的锚点
ThreadFunction _entry_point;
JNIEnv _jni_environment;
vframeArray _vframe_array_head; vframe_array的头部
vframeArray _vframe_array_last; vframe_array的尾部
GrowableArray<jvmtiDeferredLocalVariableSet> _deferred_locals_updates; 本地变量表,即localVariable,从此可以看出,本地变量表并非在栈帧中,而是并列的结构
methodOop _callee_target;
oop _vm_result;
oop _vm_result_2;
MemRegion _deferred_card_mark;
ThreadSafepointState _safepoint_state;
address _saved_exception_pc;
volatile oop _exception_oop;
volatile address _exception_pc;
volatile address _exception_handler_pc;
volatile int _exception_stack_size;
volatile int _is_method_handle_return;
———————————————————————————————————————————————–
JavaThread main_thread = new JavaThread();
调用父构造函数: Thread()
代码: new HandleMark(this);
代码: _unhandled_oops = new UnhandledOops(this);
代码: initialize();
代码: _anchor.clear();
代码: pd_initialize();
代码: _anchor.clear();
代码: _is_attaching = is_attaching;
main_thread->set_thread_state(_thread_in_vm);
线程状态共12种
enum JavaThreadState {
_thread_uninitialized = 0, // should never happen (missing initialization)
_thread_new = 2, // just starting up, i.e., in process of being initialized
_thread_new_trans = 3, // corresponding transition state (not used, included for completness)
_thread_in_native = 4, // running in native code
_thread_in_native_trans = 5, // corresponding transition state
_thread_in_vm = 6, // running in VM
_thread_in_vm_trans = 7, // corresponding transition state
_thread_in_Java = 8, // running in Java or in stub code
_thread_in_Java_trans = 9, // corresponding transition state (not used, included for completness)
_thread_blocked = 10, // blocked in vm
_thread_blocked_trans = 11, // corresponding transition state
_thread_max_state = 12 // maximum thread state+1 - used for statistics allocation
};
main_thread->record_stack_base_and_size();
main_thread->initialize_thread_local_storage();
代码: ThreadLocalStorage::set_thread(this);
代码: os::initialize_thread(); 空函数
main_thread->set_active_handles(JNIHandleBlock::allocate_block());
代码: block = new JNIHandleBlock();
代码: return block;
main_thread->set_as_starting_thread()
代码: os::create_main_thread((JavaThread)this)
代码: create_attached_thread(thread)
代码: OSThread osthread = new OSThread(NULL, NULL);
代码: osthread->set_thread_id(os::Linux::gettid()); //设置线程ID为Linux的gettid,内部代码为系统调用syscall(SYS_gettid);
代码: osthread->set_pthread_id(::pthread_self()); //设置pthreadId为当前运行的线程id
代码: os::Linux::init_thread_fpu_state();
代码: osthread->set_state(RUNNABLE);
代码: thread->set_osthread(osthread);
代码: JavaThread jt = (JavaThread )thread;
代码: address addr = jt->stack_yellow_zone_base();
代码: osthread->set_expanding_stack();
代码: os::Linux::manually_expand_stack(jt, addr);
代码: osthread->clear_expanding_stack();
代码: os::Linux::hotspot_sigmask(thread);
以上代码需要注意的是,在内部并没有调用任何os:create_thread()方法,只是将主线程设置为了osthread的threadId,因此此步骤并未生成新的thread,而是使用原thread继续运行
main_thread->create_stack_guard_pages(); 创建警戒页并把该警戒页通过::mmap函数映射到address low_addr = stack_base() - stack_size();处
main_thread->cache_global_variables(); 空函数
Threads::add(main_thread);
代码: p->initialize_queues();
代码: p->set_next(_thread_list);
代码: _thread_list = p;
代码: _number_of_threads++;
代码: ThreadService::add_thread(p, daemon);
oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0);
main_thread->set_threadObj(thread_object);
java_lang_Thread::set_thread_status(thread_object, java_lang_Thread::RUNNABLE);
在执行完毕Thread.cpp:CreateJavaVM后,在java.c中
mainClassName = GetMainClassName(env, jarfile);
classname = (char )(env)->GetStringUTFChars(env, mainClassName, 0);
mainClass = LoadClass(env, classname);
mainID = (env)->GetStaticMethodID(env, mainClass, “main”, ”([Ljava/lang/String;)V”);
jmethodID mid;
jobject obj = (env)->ToReflectedMethod(env, mainClass,mainID, JNI_TRUE);
mid = (env)->GetMethodID(env,(env)->GetObjectClass(env, obj),”getModifiers”, “()I”);
mods = (env)->CallIntMethod(env, obj, mid);
(env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); //执行java的main方法
代码: env->CallStaticVoidMethod( pClass, pMid, pArgs);
代码: functions->CallStaticVoidMethodV(this,cls,methodID,args);
代码: JavaValue jvalue(T_VOID);
JNI_ArgumentPusherVaArg ap(THREAD, methodID, args); //将参数推送到堆栈中
调用父类构造函数: JNI_ArgumentPusher(thread, JNIHandles::resolve_jmethod_id(method_id)->signature())
调用父类构造函数: SignatureIterator(thread, signature)
代码: _signature = signature;
代码: _parameter_index = 0;
代码: this->_return_type = T_ILLEGAL;
代码: _arguments = NULL;
代码: set_ap(rap);
代码: _ap = rap;
jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK); //执行static方法,参数为ap,返回值为jvalue
代码: methodHandle method(THREAD, JNIHandles::resolve_jmethod_id(method_id));
代码: ResourceMark rm(THREAD);
代码: int number_of_parameters = method->size_of_parameters();
代码: JavaCallArguments java_args(number_of_parameters);
代码: args->set_java_argument_object(&java_args);
代码: args->iterate( Fingerprinter(THREAD, method).fingerprint() ); //???????????+++++++++++++++
代码: result->set_type(args->get_ret_type());
代码: JavaCalls::call(result, method, &java_args, CHECK); invoke the method
代码: JavaCalls::call
代码: JavaCalls::call_helper
代码: JavaCallWrapper link(method, receiver, result, CHECK);
代码: address entry_point = method->from_interpreted_entry();
代码:
代码: StubRoutines::call_stub()( 调用Stub,在java中,每一个方法都会解析为一个Stub
(address)&link,
// (intptr_t)&(result->_value), // see NOTE above (compiler problem)
result_val_address, // see NOTE above (compiler problem)
result_type,
method(),
entry_point,
args->parameters(),
args->size_of_parameters(),
CHECK
);
代码: result = link.result();
代码: result->set_jobject((jobject)thread->vm_result());
代码: if (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY) {
result->set_jobject(JNIHandles::make_local(env, (oop) result->get_jobject()));
}
ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;
至此,可以看到
java.c中的launcher创建了JVM环境,然后获取到了java的main方法,然后执行jenv->CallStaticVoidMethod函数,触发了jni_invoke_static函数,之后触发了StubRoutines::call_stub()所代表的函数指针
那么问题来了,StubRoutines是什么东西,是在什么时候产生的?其内部又会对JavaThread的属性产生什么操作?其内部是如何调用到entry_point即method->from_interpreted_entry()的?
可以阅读一下R大的博客http://hllvm.group.iteye.com/group/topic/37707,权当预习。
这个行业前辈众多,需要膜拜之……例如R大,在我刚学Java之时他成名已久