hotspot源码解析-启动流程

        通用启动器是指常用的jdk命令:java。为启动一个java应用程序,java将准备一个运行时环境,加载指定的类并调用它的main方法。

启动流程

main--->JLI_Launch()--->JVMInit()--->ContinueInNewThread()
--->JavaMain()--->InitializeJVM()
--->LoadClass()--->JNI_CallStaticVoidMethod()
--->JNI_DetachCurrentThread()-->LEAVE()

打开程序入口,可以看到最后调用了JLI_Launch()函数

JLI_Launch函数最后一步要执行的JVMInit

JVMInit函数中开始通过ContinueInNewThread创建新的Java进程

 在ContinueInNewThread下有个函数ContinueInNewThread0,执行了当前的主方法JavaMain

在JavaMain中有一个InitializeJVM,表示初始化JVM。这里面最终调用了create_vm()函数来完成初始化。

 最后创建Java虚拟机进程后,回到JavaMain函数下面有这么一行, 把mainClass赋值为我们写的调用的主函数

用CallStaticVoidMethod调用我们在Java里面写的Java入口函数mainClass。LEAVE()函数表示启动器的退出代码,将会等待所有非守护进程线程结束,然后销毁虚拟机。

JVM初始化调用路径

        JNI_CreateJavaVM()函数调用Threads模块create_vm()函数完成虚拟机的创建和初始胡工作。在create_vm()函数初始化了JVM系统中绝大多数模块。下文选取该过程展开详解

InitializeJVM()--->InvocationFunctions()
--->LoadJavaVM()--->JNI_CreateJavaVM()--->Threads::create_vm()

create_vm()函数

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

/*
返回值:jint
参数1:JavaVMInitArgs*   //入参
参数2:canTryAgain       //该标志设置为1
*/
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) 
{
  extern void JDK_Version_init();

  // 仅定义接口,未实现,【11和17版本针对arm系统进行了初始化】
  VM_Version::early_initialize();

  // 检查版本信息是否为1.2 1.4 1.6 1.8
  if (!is_supported_jni_version(args->version)) return JNI_EVERSION;

  // 输出流模块初始化,设置了gc流信息从0开始,而不是第一次gc的时间戳
  ostream_init();

  // 读取args->options信息,将-Dsun.java.launcher和-Dsun.java.launcher.pid参数值储存起来
  Arguments::process_sun_java_launcher_properties(args);

  // 主要是内存、栈、线程等OS密切的部分的初始化
  os::init();

  // 设置jvm的参数和系统参数,在java中调用的System.getProperty方法的所有参数值都在自此方法中设置
  Arguments::init_system_properties();

  // 全部的初始化,包括大版本,小版本,安全,构建以及补丁的版本号,包含全部信息
  JDK_Version_init();

  // 再次设置的系统信息,java.vm.specification.vendor、java.vm.specification.version、java.vm.vendor
  Arguments::init_version_specific_system_properties();

  // Parse arguments
  // Note: this internally calls os::init_container_support()
  jint parse_result = Arguments::parse(args);
  if (parse_result != JNI_OK) return parse_result;

  /*
    关于提高jvm和gc性能的设置
    1.设置可用处理器的数量.
    2.设置lage page size
    3.设置其他特征
  */ 
  os::init_before_ergo();

  jint ergo_result = Arguments::apply_ergo();
  if (ergo_result != JNI_OK) return ergo_result;

  if (PauseAtStartup) {
    os::pause();
  }

  if (DumpSharedSpaces) {
    // when dumping shared spaces for AppCDS we must disable bytecode
    // rewriting as it initializes internal (cached) meta-data that
    // would be stored in the archive but cannot be carried over to
    // the next execution
    RewriteBytecodes = false;
  }

#ifndef USDT2
  HS_DTRACE_PROBE(hotspot, vm__init__begin);
#else /* USDT2 */
  HOTSPOT_VM_INIT_BEGIN();
#endif /* USDT2 */

  // 记录VM创建时间统计信息
  TraceVmCreationTime create_vm_timer;
  create_vm_timer.start();

 // Timing (must come after argument parsing)
  TraceTime timer("Create VM", TraceStartupTime);

 /*
 OS模块的二次初始化,包含线程锁的初始,polling_page和mem_serialize_page分配内存,
 信号处理初始化,设置线程栈大小,libpthread初始化,设置线程锁,线程优先级策略的初始化
 */
  jint os_init_2_result = os::init_2();
  if (os_init_2_result != JNI_OK) return os_init_2_result;

  //UseNUMA时额外的参数设置
  jint adjust_after_os_result = Arguments::adjust_after_os();
  if (adjust_after_os_result != JNI_OK) return adjust_after_os_result;

  // 初始化TLS
  ThreadLocalStorage::init();

  // 初始化GC日志和LoadedClass日志的fileStream对象
  ostream_init_log();

  // 将参数-Xrun 转换成 -agentlib参数
  // Convert -Xrun to -agentlib: if there is no JVM_OnLoad
  // Must be before create_vm_init_agents()
  if (Arguments::init_libraries_at_startup()) {
    convert_vm_init_libraries_to_agents();
  }

  //根据-agentlib/-agentpath and 转换后 -Xrun参数创建agents
  if (Arguments::init_agents_at_startup()) {
    create_vm_init_agents();
  }

  // Initialize Threads state
  _thread_list = NULL;
  _number_of_threads = 0;
  _number_of_non_daemon_threads = 0;

  // 初始化Events,各种锁,ChunkPool,PerfMemory
  vm_init_globals();

  
  /*
  创建一个新的JavaThread并设置相关属性,注意这里并未创建一个新的线程,
  而是将当前线程同JavaThread对象关联起来,通过JavaThread管理相关属性
  */
  JavaThread* main_thread = new JavaThread();
  main_thread->set_thread_state(_thread_in_vm);
  // must do this before set_active_handles and initialize_thread_local_storage
  // Note: on solaris initialize_thread_local_storage() will (indirectly)
  // change the stack size recorded here to one based on the java thread
  // stacksize. This adjusted size is what is used to figure the placement
  // of the guard pages.
  main_thread->record_stack_base_and_size();
  main_thread->initialize_thread_local_storage();

  main_thread->set_active_handles(JNIHandleBlock::allocate_block());

  if (!main_thread->set_as_starting_thread()) {
    vm_shutdown_during_initialization(
      "Failed necessary internal allocation. Out of swap space");
    delete main_thread;
    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
    return JNI_ENOMEM;
  }

  // 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();

  // Initialize Java-Level synchronization subsystem
  ObjectMonitor::Initialize() ;

  /*
    全局模块初始化,如Management模块,Bytecodes模块,ClassLoader模块,
    CodeCache模块,StubRoutines模块,Universe模块,Interpreter模块等
  */
  jint status = init_globals();
  if (status != JNI_OK) {
    delete main_thread;
    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
    return status;
  }

  JFR_ONLY(Jfr::on_vm_init();)

  // Should be done after the heap is fully created
  main_thread->cache_global_variables();

  HandleMark hm;


  { MutexLocker mu(Threads_lock);
    //将线程加入线程队列
    Threads::add(main_thread);
  }

  // Any JVMTI raw monitors entered in onload will transition into
  // real raw monitor. VM is setup enough here for raw monitor enter.
  JvmtiExport::transition_pending_onload_raw_monitors();

  // Create the VMThread,创建虚拟机线程
  { TraceTime timer("Start VMThread", TraceStartupTime);
    VMThread::create();
    Thread* vmthread = VMThread::vm_thread();

    if (!os::create_thread(vmthread, os::vm_thread))
      vm_exit_during_initialization("Cannot create VM thread. Out of system resources.");

    //等待VMThread初始化完成
    // Wait for the VM thread to become ready, and VMThread::run to initialize
    // Monitors can have spurious returns, must always check another state flag
    {
      MutexLocker ml(Notify_lock);
      os::start_thread(vmthread);
      while (vmthread->active_handles() == NULL) {
        Notify_lock->wait();
      }
    }
  }

  assert (Universe::is_fully_initialized(), "not initialized");
  if (VerifyDuringStartup) {
    // Make sure we're starting with a clean slate.
   //验证VMThread的状态
    VM_Verify verify_op;
    VMThread::execute(&verify_op);
  }

  EXCEPTION_MARK;

  // At this point, the Universe is initialized, but we have not executed
  // any byte code.  Now is a good time (the only time) to dump out the
  // internal state of the JVM for sharing, unless AppCDS is enabled.
  if (!UseAppCDS && DumpSharedSpaces) {
    //Dump元空间
    MetaspaceShared::preload_and_dump(CHECK_0);
    ShouldNotReachHere();
  }

  //标记JVMTI启用
  // Always call even when there are not JVMTI environments yet, since environments
  // may be attached late and JVMTI must track phases of VM execution
  JvmtiExport::enter_start_phase();

  //通知JVMTI agents虚机已启动
  // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.
  JvmtiExport::post_vm_start();
  //加载核心Java类文件
  {
    TraceTime timer("Initialize java.lang classes", TraceStartupTime);

    if (EagerXrunInit && Arguments::init_libraries_at_startup()) {
      create_vm_init_libraries();
    }

    initialize_class(vmSymbols::java_lang_String(), CHECK_0);

    // Initialize java_lang.System (needed before creating the thread)
    initialize_class(vmSymbols::java_lang_System(), CHECK_0);
    initialize_class(vmSymbols::java_lang_ThreadGroup(), CHECK_0);
    Handle thread_group = create_initial_thread_group(CHECK_0);
    Universe::set_main_thread_group(thread_group());
    initialize_class(vmSymbols::java_lang_Thread(), CHECK_0);
    oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0);
    main_thread->set_threadObj(thread_object);
    // Set thread status to running since main thread has
    // been started and running.
    java_lang_Thread::set_thread_status(thread_object,
                                        java_lang_Thread::RUNNABLE);

    // The VM creates & returns objects of this class. Make sure it's initialized.
    initialize_class(vmSymbols::java_lang_Class(), CHECK_0);

    // The VM preresolves methods to these classes. Make sure that they get initialized
    initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK_0);
    initialize_class(vmSymbols::java_lang_ref_Finalizer(),  CHECK_0);
    call_initializeSystemClass(CHECK_0);

    // get the Java runtime name after java.lang.System is initialized
    JDK_Version::set_runtime_name(get_java_runtime_name(THREAD));
    JDK_Version::set_runtime_version(get_java_runtime_version(THREAD));

    // an instance of OutOfMemory exception has been allocated earlier
    initialize_class(vmSymbols::java_lang_OutOfMemoryError(), CHECK_0);
    initialize_class(vmSymbols::java_lang_NullPointerException(), CHECK_0);
    initialize_class(vmSymbols::java_lang_ClassCastException(), CHECK_0);
    initialize_class(vmSymbols::java_lang_ArrayStoreException(), CHECK_0);
    initialize_class(vmSymbols::java_lang_ArithmeticException(), CHECK_0);
    initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK_0);
    initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK_0);
    initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK_0);
  }

  // See        : bugid 4211085.
  // Background : the static initializer of java.lang.Compiler tries to read
  //              property"java.compiler" and read & write property "java.vm.info".
  //              When a security manager is installed through the command line
  //              option "-Djava.security.manager", the above properties are not
  //              readable and the static initializer for java.lang.Compiler fails
  //              resulting in a NoClassDefFoundError.  This can happen in any
  //              user code which calls methods in java.lang.Compiler.
  // Hack :       the hack is to pre-load and initialize this class, so that only
  //              system domains are on the stack when the properties are read.
  //              Currently even the AWT code has calls to methods in java.lang.Compiler.
  //              On the classic VM, java.lang.Compiler is loaded very early to load the JIT.
  // Future Fix : the best fix is to grant everyone permissions to read "java.compiler" and
  //              read and write"java.vm.info" in the default policy file. See bugid 4211383
  //              Once that is done, we should remove this hack.
  initialize_class(vmSymbols::java_lang_Compiler(), CHECK_0);

  // More hackery - the static initializer of java.lang.Compiler adds the string "nojit" to
  // the java.vm.info property if no jit gets loaded through java.lang.Compiler (the hotspot
  // compiler does not get loaded through java.lang.Compiler).  "java -version" with the
  // hotspot vm says "nojit" all the time which is confusing.  So, we reset it here.
  // This should also be taken out as soon as 4211383 gets fixed.
  //将java.vm.info设置成nojit
  reset_vm_info_property(CHECK_0);

  //初始化JNIEnv中GetField相关接口
  quicken_jni_functions();

  // Set flag that basic initialization has completed. Used by exceptions and various
  // debug stuff, that does not work until all basic classes have been initialized.
  // 设置初始化完成标识
  set_init_completed();

  //元空间的预初始化
  Metaspace::post_initialize();

#ifndef USDT2
  HS_DTRACE_PROBE(hotspot, vm__init__end);
#else /* USDT2 */
  HOTSPOT_VM_INIT_END();
#endif /* USDT2 */

  // record VM initialization completion time
#if INCLUDE_MANAGEMENT
  // 记录初始化完成时间
  Management::record_vm_init_completed();
#endif // INCLUDE_MANAGEMENT

  // Compute system loader. Note that this has to occur after set_init_completed, since
  // valid exceptions may be thrown in the process.
  // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and
  // set_init_completed has just been called, causing exceptions not to be shortcut
  // anymore. We call vm_exit_during_initialization directly instead.
  SystemDictionary::compute_java_system_loader(THREAD);
  if (HAS_PENDING_EXCEPTION) {
    vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
  }

  if (UseAppCDS && DumpSharedSpaces) {
    MetaspaceShared::preload_and_dump(CHECK_0);
    ShouldNotReachHere();
  }

#if INCLUDE_ALL_GCS
  // Support for ConcurrentMarkSweep. This should be cleaned up
  // and better encapsulated. The ugly nested if test would go away
  // once things are properly refactored. XXX YSR
 //并发标记的初始化,会创建一个新的执行标记的线程
  if (UseConcMarkSweepGC || UseG1GC) {
    if (UseConcMarkSweepGC) {
      ConcurrentMarkSweepThread::makeSurrogateLockerThread(THREAD);
    } else {
      ConcurrentMarkThread::makeSurrogateLockerThread(THREAD);
      G1CollectedHeap::heap()->init_periodic_gc_thread();
    }
    if (HAS_PENDING_EXCEPTION) {
      vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
    }
  }
#endif // INCLUDE_ALL_GCS

  // Always call even when there are not JVMTI environments yet, since environments
  // may be attached late and JVMTI must track phases of VM execution
  //JVMTI打标,标识JVM进入可用状态
  JvmtiExport::enter_live_phase();

  // Signal Dispatcher needs to be started before VMInit event is posted
  //创建一个新的线程处理信号
  os::signal_init();

  // Start Attach Listener if +StartAttachListener or it can't be started lazily
  if (!DisableAttachMechanism) {
    //移除.java_pid文件,准备好初始化
    AttachListener::vm_start();
    if (StartAttachListener || AttachListener::init_at_startup()) {
      AttachListener::init();
    }
  }

  // Launch -Xrun agents
  // Must be done in the JVMTI live phase so that for backward compatibility the JDWP
  // back-end can launch with -Xdebug -Xrunjdwp.
  //加载-Xrun执行的agent 库
  if (!EagerXrunInit && Arguments::init_libraries_at_startup()) {
    create_vm_init_libraries();
  }

  //通知JVMTI JVM初始化完成
  // Notify JVMTI agents that VM initialization is complete - nop if no agents.
  JvmtiExport::post_vm_initialized();

  JFR_ONLY(Jfr::on_vm_start();)

  //开启一个新的线程用于清理ChunkPool
  if (CleanChunkPoolAsync) {
    Chunk::start_chunk_pool_cleaner_task();
  }

  // c1 和 c2编译器初始化,会创建编译线程
#if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK)
  CompileBroker::compilation_init();
#endif

  //加载动态代理相关类
  if (EnableInvokeDynamic) {
    // Pre-initialize some JSR292 core classes to avoid deadlock during class loading.
    // It is done after compilers are initialized, because otherwise compilations of
    // signature polymorphic MH intrinsics can be missed
    // (see SystemDictionary::find_method_handle_intrinsic).
    initialize_class(vmSymbols::java_lang_invoke_MethodHandle(), CHECK_0);
    initialize_class(vmSymbols::java_lang_invoke_MemberName(), CHECK_0);
    initialize_class(vmSymbols::java_lang_invoke_MethodHandleNatives(), CHECK_0);
  }

#if INCLUDE_MANAGEMENT
  //加载Management相关类
  Management::initialize(THREAD);
#endif // INCLUDE_MANAGEMENT

  //management加载失败,退出
  if (HAS_PENDING_EXCEPTION) {
    // management agent fails to start possibly due to
    // configuration problem and is responsible for printing
    // stack trace if appropriate. Simply exit VM.
    vm_exit(1);
  }

  //初始化监控任务线程
  if (Arguments::has_profile())       FlatProfiler::engage(main_thread, true);
  if (MemProfiling)                   MemProfiler::engage();
  StatSampler::engage();
  if (CheckJNICalls)                  JniPeriodicChecker::engage();
  
//偏向锁的初始化
  BiasedLocking::init();

#if INCLUDE_RTM_OPT
  RTMLockingCounters::init();
#endif

  //回调函数,通知其JVM初始化完成
  if (JDK_Version::current().post_vm_init_hook_enabled()) {
    call_postVMInitHook(THREAD);
    // The Java side of PostVMInitHook.run must deal with all
    // exceptions and provide means of diagnosis.
    if (HAS_PENDING_EXCEPTION) {
      CLEAR_PENDING_EXCEPTION;
    }
  }

  {
      MutexLockerEx ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
      // Make sure the watcher thread can be started by WatcherThread::start()
      // or by dynamic enrollment.
      WatcherThread::make_startable();
      // Start up the WatcherThread if there are any periodic tasks
      // NOTE:  All PeriodicTasks should be registered by now. If they
      //   aren't, late joiners might appear to start slowly (we might
      //   take a while to process their first tick).
      if (PeriodicTask::num_tasks() > 0) {
          WatcherThread::start();
      }
  }

  //标记JVM启动完成
  create_vm_timer.end();
#ifdef ASSERT
  _vm_complete = true;
#endif
  return JNI_OK;
}

os:init()函数

// this is called _before_ the most of global arguments have been parsed
void os::init(void) {
  char dummy;   /* used to get a guess on initial stack address */
//  first_hrtime = gethrtime();

  // With BsdThreads the JavaMain thread pid (primordial thread)
  // is different than the pid of the java launcher thread.
  // So, on Bsd, the launcher thread pid is passed to the VM
  // via the sun.java.launcher.pid property.
  // Use this property instead of getpid() if it was correctly passed.
  // See bug 6351349.
  pid_t java_launcher_pid = (pid_t) Arguments::sun_java_launcher_pid();

  _initial_pid = (java_launcher_pid > 0) ? java_launcher_pid : getpid();

  clock_tics_per_sec = CLK_TCK;

  init_random(1234567);

  ThreadCritical::initialize();
  
  设置系统页大小
  Bsd::set_page_size(getpagesize());
  if (Bsd::page_size() == -1) {
    fatal(err_msg("os_bsd.cpp: os::init: sysconf failed (%s)",
                  strerror(errno)));
  }
  init_page_sizes((size_t) Bsd::page_size());

  //设置处理器数量、获得物理内存大小
  Bsd::initialize_system_info();

  //保存当前线程ID
  // _main_thread points to the thread that created/loaded the JVM.
  Bsd::_main_thread = pthread_self();

  //设置系统时钟
  Bsd::clock_init();
  initial_time_count = javaTimeNanos();

#ifdef __APPLE__
  // XXXDARWIN
  // Work around the unaligned VM callbacks in hotspot's
  // sharedRuntime. The callbacks don't use SSE2 instructions, and work on
  // Linux, Solaris, and FreeBSD. On Mac OS X, dyld (rightly so) enforces
  // alignment when doing symbol lookup. To work around this, we force early
  // binding of all symbols now, thus binding when alignment is known-good.
  _dyld_bind_fully_image_containing_address((const void *) &os::init);
#endif
}

os::init_2()函数

// this is called _after_ the global arguments have been parsed
jint os::init_2(void)
{
   /*
    通过系统调用mmap分配一个可读的单页内存,用于安全点的轮循。
    这里介绍一下这个内存页的用处`polling_page`与JVM的垃圾回收机制相关,用于在线程间进行通信,
    因为JVM中用户工作线程和GC线程。
    具体来说,就是线程通过在`polling_page`上进行轮询,等待特殊的信号或标记,
    以知道何时有工作需要执行。这种轮询目的就是为了允许垃圾回收器在并发阶段与用户工作线程
    并发执行,以减小垃圾收集带来的暂停时间。
  */
  // Allocate a single page and mark it as readable for safepoint polling
  address polling_page = (address) ::mmap(NULL, Bsd::page_size(), PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  guarantee( polling_page != MAP_FAILED, "os::init_2: failed to allocate polling page" );
  
  // 设置`polling_page`
  os::set_polling_page( polling_page );

#ifndef PRODUCT
  if(Verbose && PrintMiscellaneous)
    tty->print("[SafePoint Polling address: " INTPTR_FORMAT "]\n", (intptr_t)polling_page);
#endif
 /*
 * UseMembar 为 true 表示使用内存屏障(memory barrier),内存屏障是一种硬件或编译器指令,用于确保内存操作
 * 按照代码书写的顺序执行的机制。
 * 在多线程编程中,由于线程之间的执行顺序是不确定的,可能导致一些意外的情况,比如数据竞争、缓存一致性问题等。
 * Hotspot membar 提供了一种方式来显示地指示内存屏障,以确保在内存中进行的读写操作的顺序性和可见性。
 * 具体来讲,Hotspot membar内存屏障可用于:
 * 1.防止指令重排序:内存屏障可防止对指令进行优化和重排序,确保代码的执行顺序与编写顺序一致
 * 2.保证内存可见性:内存屏障可确保一个线程写入的数据对其他线程是可见的,避免由于线程间缓存不一致性导致的问题
 * 3.实现同步机制:在多线程环境中,使用内存屏障可以实现一些同步机制,比如在临界区前后插入内存屏障,以确保线程
 * 按照期望的顺序执行。
 */
  if (!UseMembar) {
 // 这里的意思是虚拟机没有开放内存屏障,就用系统调用mmap分配一个页大小的内存操作来代替,现在知道有这个东西就行,后面在讲解安全点知识时会细讲这个的作用
    address mem_serialize_page = (address) ::mmap(NULL, Bsd::page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    guarantee( mem_serialize_page != MAP_FAILED, "mmap Failed for memory serialize page");
    os::set_memory_serialize_page( mem_serialize_page );

#ifndef PRODUCT
    if(Verbose && PrintMiscellaneous)
      tty->print("[Memory Serialize  Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page);
#endif
  }

  //初始化内核信号
  // initialize suspend/resume support - must do this before signal_sets_init()
  if (SR_initialize() != 0) {
    perror("SR_initialize failed");
    return JNI_ERR;
  }
  
  //继续系统级别的信号初始化,比如SIGSEGV、SIGBUS等
  Bsd::signal_sets_init();
 // 给对应的信号安装/设置处理器程序
  Bsd::install_signal_handlers();

  // Check minimum allowable stack size for thread creation and to initialize
  // the java system classes, including StackOverflowError - depends on page
  // size.  Add a page for compiler2 recursion in main thread.
  // Add in 2*BytesPerWord times page size to account for VM stack during
  // class initialization depending on 32 or 64 bit VM.
  // 校验最小的线程栈大小,默认最小就是64k
  os::Bsd::min_stack_allowed = MAX2(os::Bsd::min_stack_allowed,
            (size_t)(StackYellowPages+StackRedPages+StackShadowPages+
                    2*BytesPerWord COMPILER2_PRESENT(+1)) * Bsd::page_size());
 
 // 拿到默认设置/用户设置的ThreadStackSize
  size_t threadStackSizeInBytes = ThreadStackSize * K;
// 比较,如果ThreadStackSize太小,就报错,退出
  if (threadStackSizeInBytes != 0 &&
      threadStackSizeInBytes < os::Bsd::min_stack_allowed) {
        tty->print_cr("\nThe stack size specified is too small, "
                      "Specify at least %dk",
                      os::Bsd::min_stack_allowed/ K);
        return JNI_ERR;
  }

  // Make the stack size a multiple of the page size so that
  // the yellow/red zones can be guarded.
  JavaThread::set_stack_size_at_create(round_to(threadStackSizeInBytes,
        vm_page_size()));

   // 设置最大文件描述符限制
  if (MaxFDLimit) {
    // set the number of file descriptors to max. print out error
    // if getrlimit/setrlimit fails but continue regardless.
    struct rlimit nbr_files;
    int status = getrlimit(RLIMIT_NOFILE, &nbr_files);
    if (status != 0) {
      if (PrintMiscellaneous && (Verbose || WizardMode))
        perror("os::init_2 getrlimit failed");
    } else {
      nbr_files.rlim_cur = nbr_files.rlim_max;

#ifdef __APPLE__
      // Darwin returns RLIM_INFINITY for rlim_max, but fails with EINVAL if
      // you attempt to use RLIM_INFINITY. As per setrlimit(2), OPEN_MAX must
      // be used instead
      nbr_files.rlim_cur = MIN(OPEN_MAX, nbr_files.rlim_cur);
#endif

      status = setrlimit(RLIMIT_NOFILE, &nbr_files);
      if (status != 0) {
        if (PrintMiscellaneous && (Verbose || WizardMode))
          perror("os::init_2 setrlimit failed");
      }
    }
  }

  // at-exit methods are called in the reverse order of their registration.
  // atexit functions are called on return from main or as a result of a
  // call to exit(3C). There can be only 32 of these functions registered
  // and atexit() does not set errno.

  if (PerfAllowAtExitRegistration) {
    // only register atexit functions if PerfAllowAtExitRegistration is set.
    // atexit functions can be delayed until process exit time, which
    // can be problematic for embedded VM situations. Embedded VMs should
    // call DestroyJavaVM() to assure that VM resources are released.

    // note: perfMemory_exit_helper atexit function may be removed in
    // the future if the appropriate cleanup code can be added to the
    // VM_Exit VMOperation's doit method.
    if (atexit(perfMemory_exit_helper) != 0) {
      warning("os::init2 atexit(perfMemory_exit_helper) failed");
    }
  }

  // // 初始化线程优先级策略,主要分为-1(线程初始化状态时,没有等级)、1、5、9、10/11 5个等级
  prio_init();

#ifdef __APPLE__
  // dynamically link to objective c gc registration
  void *handleLibObjc = dlopen(OBJC_LIB, RTLD_LAZY);
  if (handleLibObjc != NULL) {
    objc_registerThreadWithCollectorFunction = (objc_registerThreadWithCollector_t) dlsym(handleLibObjc, OBJC_GCREGISTER);
  }
#endif

  return JNI_OK;
}

SR_initialize()函数

static int SR_initialize() {
  struct sigaction act;
  char *s;
  //通过环境变量_JAVA_SR_SIGNUM获取初始信号值
  /* Get signal number to use for suspend/resume */
  if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) {
    int sig = ::strtol(s, 0, 10);
    if (sig > 0 || sig < NSIG) {
        SR_signum = sig;
    }
  }

  assert(SR_signum > SIGSEGV && SR_signum > SIGBUS,
        "SR_signum must be greater than max(SIGSEGV, SIGBUS), see 4355769");
  //清空信号集
  sigemptyset(&SR_sigset);
  //添加信号至信号集
  sigaddset(&SR_sigset, SR_signum);

  /* 设置挂起/恢复的信号处理程序 */
  act.sa_flags = SA_RESTART|SA_SIGINFO;
  act.sa_handler = (void (*)(int)) SR_handler;

  // SR_signum is blocked by default.
  // 4528190 - We also need to block pthread restart signal (32 on all
  // supported Bsd platforms). Note that BsdThreads need to block
  // this signal for all threads to work properly. So we don't have
  // to use hard-coded signal number when setting up the mask.
  //获取当前线程信号屏蔽码
  pthread_sigmask(SIG_BLOCK, NULL, &act.sa_mask);
  
  //给信号指定相关的处理程序
  if (sigaction(SR_signum, &act, 0) == -1) {
    return -1;
  }

  // Save signal flag  保存信号标志
  os::Bsd::set_our_sigflags(SR_signum, act.sa_flags);
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值