HotSpot 启动流程

本篇是JVM系列开篇,主要分析JVM的启动流程。JVM系列主要以HotSpot为主,按HotSpot各模块来一一展开,包括Class类文件成分,字节码文件加载及解析,HotSpot内存结构,JVM解析器,Kclass-Oop模型,垃圾回收器,执行引擎,字节码指令系统,JIT, AOT, 逃逸分析,栈顶缓存等等。

一. HotSpot的组成结构

JVM(全称Java Virtual Machine), 是一台虚拟的计算机,本身不跨平台。是Java,Python等编程语言生成的字节码文件的执行平台。具体的JVM可以由JRockit,HotSpot 等多种实现。但是需要遵循JVM规范,以实现语言的跨平台兼容性。最新的graalvm是一个多语言通用虚拟机。

HotSpot的组成包括:

1.类加载器子系统:负责加载二进制字节码文件流。
2.内存模型:Java栈,本地方法栈,Java堆,方法区,PC寄存器,直接内存
3.垃圾收集器:主要负责Java堆空间内存回收。
4.类文件解析器:解析二进制流字节码文件为对象模型
5.对象模型:虚拟机内部klass-Oop模型
6.解释器:虚拟机内部字节码执行单元,包括字节码解释器,模板解释器
7.编译器:虚拟机内置编译器,字节码指令的动态优化,包括JIT, AOT
8.监控: 虚拟机对外提供的运行时统计监控
9.运行时:虚拟机运行时环境
10.服务:虚拟机内部服务,包括内存,线程,运行时,类加载服务
11.os模块:负责与具体的寄生系统交互

二.HotSpot的启动流程

上一篇我们编译JDK, 和断点java命令,现在我们实际断点一个java Hello,打开Clion->Configurations
按如下配置:
在这里插入图片描述
jdk/src/java.base/share/native/launcher/main.c 这是java命令启动入口,在main()函数前打上断点
开始跟踪JVM的启动 main() -> JLI_Launch
在这里插入图片描述

1.初始化准备

jdk/src/java.base/share/native/libjli/java.c
断点到main函数末尾,调用JLI_Launch

//操作libjvm.so
typedef struct {
    CreateJavaVM_t CreateJavaVM;
    GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs;
    GetCreatedJavaVMs_t GetCreatedJavaVMs;
} InvocationFunctions;

//由main.c的main()函数调用
int JLI_Launch(int argc, char ** argv,              /* main argc, argc */
        int jargc, const char** jargv,          /* java args */
        ......                             
)
{
 ......
 InvocationFunctions ifn; //结构体
 ......
 
 ifn.CreateJavaVM = 0;
 ifn.GetDefaultJavaVMInitArgs = 0;
 
 if (!LoadJavaVM(jvmpath, &ifn)) { //加载libjvm.so
        return(6);
    }
 //启动属性设置
  ......
 //初始化JVM
 return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);
}

jdk/src/java.base/unix/native/libjli/java_md_solinux.c
加载libjvm.so,绑定InvocationFunctions

jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn){ //
    libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
    ifn->CreateJavaVM = (CreateJavaVM_t) dlsym(libjvm, "JNI_CreateJavaVM");
    ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
        dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
    ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
        dlsym(libjvm, "JNI_GetCreatedJavaVMs");
   return JNI_TRUE;
}

jdk/src/java.base/unix/native/libjli/java_md_solinux.c
初始化JVM

//调用 ContinueInNewThread
int JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
        int argc, char **argv,
        int mode, char *what, int ret)
{
    ShowSplashScreen();
    return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
}

jdk/src/java.base/share/native/libjli/java.c
创建一个新线程去创建JVM,调用JavaMain

ContinueInNewThread(InvocationFunctions* ifn, jlong threadStackSize,
                    int argc, char **argv,
                    int mode, char *what, int ret)
{
   //设置线程栈大小
   if (threadStackSize == 0) {
      struct JDK1_1InitArgs args1_1;
      memset((void*)&args1_1, 0, sizeof(args1_1));
      args1_1.version = JNI_VERSION_1_1;
      ifn->GetDefaultJavaVMInitArgs(&args1_1);  /* ignore return value */
      if (args1_1.javaStackSize > 0) {
         threadStackSize = args1_1.javaStackSize;
      }
    }
    
    { /* Create a new thread to create JVM and invoke main method */
      JavaMainArgs args;
      int rslt;
      args.argc = argc;
      ......
      args.ifn = *ifn;
      rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args);
}

jdk/src/java.base/unix/native/libjli/java_md_solinux.c

int ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
    int rslt;
#ifndef __solaris__
    ......
    //创建线程
    if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {
      void * tmp;
      pthread_join(tid, &tmp);
      rslt = (int)(intptr_t)tmp;
    } else {
      //调用JavaMain
      rslt = continuation(args);
    }
    ......
#else /* __solaris__ */
    ......
    return rslt;

jdk/src/java.base/share/native/libjli/java.c
执行JavaMain函数

int JNICALL JavaMain(void * _args) {
    JavaMainArgs *args = (JavaMainArgs *)_args;
    ......
    InvocationFunctions ifn = args->ifn;
    //初始化虚拟机
    start = CounterGet();
    if (!InitializeJVM(&vm, &env, &ifn)) {
        JLI_ReportErrorMessage(JVM_ERROR1);
        exit(1);
    }
    ......
    //加载Hello类
   mainClass = LoadMainClass(env, mode, what); 
   appClass = GetApplicationClass(env);
   //获取Hello类的main方法
   mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
                                       "([Ljava/lang/String;)V");
  //调用main()方法
  (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
  
  //结束
  LEAVE();
}

//初始化据JVM

......
static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn)
{
    JavaVMInitArgs args;
    jint r;
    memset(&args, 0, sizeof(args));
    args.version  = JNI_VERSION_1_2;
    args.nOptions = numOptions;
    args.options  = options;
    args.ignoreUnrecognized = JNI_FALSE;
    r = ifn->CreateJavaVM(pvm, (void **)penv, &args); //进入到libjvm.so
    JLI_MemFree(options);
    return r == JNI_OK;
}

2.进入JVM

hotspot/src/share/vm/prims/jni.cpp
进入JVM初始化阶段,prims模块是外部与JVM交互模块

_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) {
  jint result = 0;
  result = JNI_CreateJavaVM_inner(vm, penv, args); //调用(如下)
  return result;
}
static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) {
  HOTSPOT_JNI_CREATEJAVAVM_ENTRY((void **) vm, penv, args);
  jint result = JNI_ERR;
  ......
  //创建VM
  result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again);
  if (result == JNI_OK) {
    JavaThread *thread = JavaThread::current();
    /* thread is thread_in_vm here */
    *vm = (JavaVM *)(&main_vm);
    *(JNIEnv**)penv = thread->jni_environment();
    ......
    //跟踪应用
    RuntimeService::record_application_start();
    ......

  return result;
}

3.初始化JVM

hotspot/src/share/vm/runtime/thread.cpp

执行初始化,主要分三个阶段:
第一阶段:HOTSPOT_VM_INIT_BEGIN -> HOTSPOT_VM_INIT_END
第二阶段:call_initPhase2
第三阶段:call_initPhase3

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
  .....
  //TLS初始化
  ThreadLocalStorage::init();
  // 输入输出流初始化
  ostream_init();
  //os模块初始化
  os::init();
  os::init_before_ergo();
  //VM初始化开始
  HOTSPOT_VM_INIT_BEGIN();
  //初始化全局数据结构并在堆中创建系统类
  vm_init_globals();
  //Attach线程
  JavaThread* main_thread = new JavaThread();
  main_thread->set_thread_state(_thread_in_vm);
  main_thread->initialize_thread_current();
  // 线程栈基和栈大小
  main_thread->record_stack_base_and_size();
  main_thread->set_active_handles(JNIHandleBlock::allocate_block());
  // Enable guard page *after* os::create_main_thread(), otherwise it would
  // crash Linux VM, see notes in os_linux.cpp.
  main_thread->create_stack_guard_pages();
  //初始化Java级同步子系统
  ObjectMonitor::Initialize();
  // 初始化全局模块
  jint status = init_globals();
  
  // Should be done after the heap is fully created
  main_thread->cache_global_variables();
  //初始化java/lang下的类
  initialize_java_lang_classes(main_thread, CHECK_JNI_ERR);
  //标记初始化完成
  set_init_completed();
  //元空间初始化
  Metaspace::post_initialize();
  HOTSPOT_VM_INIT_END();

  // 预先初始化一些JSR292核心类,String,System,Class类
  initialize_jsr292_core_classes(CHECK_JNI_ERR);

  // 这将初始化模块系统。只有java.base类可以是加载到阶段2完成
  call_initPhase2(CHECK_JNI_ERR);

  // 即使还没有JVMTI环境,也要始终调用,因为环境可能会延迟连接,而且JVMTI必须跟踪VM执行的各个阶段
  JvmtiExport::enter_start_phase();

  // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.
  JvmtiExport::post_vm_start();

  //最终系统初始化,包括安全管理器和系统类加载器
  call_initPhase3(CHECK_JNI_ERR);

  // 缓存系统类加载器
  SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR));

  //即使还没有JVMTI环境,也要始终调用,因为环境可能会延迟连接,而且JVMTI必须跟踪VM执行的各个阶段
  JvmtiExport::enter_live_phase();

  //通知初始化完成
  JvmtiExport::post_vm_initialized();
  ......
  
#ifdef ASSERT
  _vm_complete = true;
#endif
  return JNI_OK; //JVM初始化完成

}

hotspot/src/share/vm/runtime/init.cpp
初始化全局数据结构并在堆中创建系统类

void vm_init_globals() {
  check_ThreadShadow();
  basic_types_init(); //heapOopSize与压缩指针
  eventlog_init(); //一些事件
  mutex_init();// 全局监视器和互斥体
  chunkpool_init();//四个ChunkPool
  perfMemory_init();//监控内存初始化
  SuspendibleThreadSet_init();
}

hotspot/src/share/vm/runtime/init.cpp
初始化全局模块

jint init_globals() {
  HandleMark hm;
  management_init(); //监控服务,线程服务,运行时服务,类加载服务初始化
  bytecodes_init(); // 字节码解释器初始化
  classLoader_init1(); //类加载器初始化第一阶段:zip,jimage入口,设置启动类路径
  compilationPolicy_init();//编译策略,根据编译等级确定从c1,c2编译器
  codeCache_init();//代码缓存初始化
  VM_Version_init();
  os_init_globals();
  stubRoutines_init1();//例程初始化第一阶段,例程:代码调用点
  //堆空间,元空间,AOTLoader,SymbolTable,StringTable,G1收集器初始化
  jint status = universe_init(); 
  if (status != JNI_OK)
    return status;

  interpreter_init();  // 模板解释器初始化
  invocationCounter_init();  //热点统计初始化
  marksweep_init();//标记清除GC初始化
  accessFlags_init();
  templateTable_init();//模板表初始化
  InterfaceSupport_init();
  SharedRuntime::generate_stubs();//生成部分例程入口
  universe2_init();  // vmSymbols,系统字典,预加载类,构建基本数据对象模型
  referenceProcessor_init();//对象引用策略
  jni_handles_init();//JNI引用句柄
#if INCLUDE_VM_STRUCTS
  vmStructs_init(); //一些相关数据结构
#endif // INCLUDE_VM_STRUCTS

  vtableStubs_init();//虚表例程初始化
  InlineCacheBuffer_init();//内联缓冲初始化
  compilerOracle_init();//Oracle相关的初始化
  dependencyContext_init();//监控统计相关

  if (!compileBroker_init()) {
    return JNI_EINVAL;
  }
  VMRegImpl::set_regName(); //虚拟机寄存器初始化

  if (!universe_post_init()) {//初始化必要的类,注册堆空间到内存服务
    return JNI_ERR;
  }
  javaClasses_init();   //java基础类相关计算
  stubRoutines_init2(); // 例程初始化第二阶段,模板解释器继承体系初始化
  MethodHandles::generate_adapters();//方法与代码缓存点适配

  return JNI_OK;
}

至此HotSpot虚拟机初始化完毕,将返回java.c的JavaMain函数继续往下加载Hello主类并找到Hello类的静态main方法并执行,执行完毕后LEAVE(),退出。在ContinueInNewThread0中创建2号线程来完成后续初始化。HotSpot的初始化过程中集中体现在init_globals()中各模块的初始化,从最基础的监控,服务,类加载器初始化为后续各阶段的初始化做准备。后续包括解释器,类加载器,堆空间,编译器,收集器等各模块逐一初始化为HotSpot的运行做好准备。

HotSpot的初始化启动过程就是上述这些,中间省略掉了一些以凸显主要流程。下一篇将从类加载器出发分析HotSpot的类加载机制。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值