Hotspot源码解析-第九章

发布时间:2023年12月28日

第九章

9.1 OS初始化2

9.1.1 os_linux.cpp

9.1.1.1 os::init_2

这个函数是在全部参数都解析后调用的

jint os::init_2(void)
{
  Linux::fast_thread_clock_init();

  // Allocate a single page and mark it as readable for safepoint polling
  /*
  * 通过系统调用mmap分配一个可读的单页内存,用于安全点的轮循。这里介绍一下这个内存页的用处
  * `polling_page`与JVM的垃圾回收机制相关,用于在线程间进行通信,因为JVM中用户工作线程和GC线程。具体来说,
  * 就是线程通过在`polling_page`上进行轮询,等待特殊的信号或标记,以知道何时有工作需要执行。这种轮询目的就是为
  * 了允许垃圾回收器在并发阶段与用户工作线程并发执行,以减小垃圾收集带来的暂停时间。
  */
  address polling_page = (address) ::mmap(NULL, Linux::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, Linux::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
  }

  // 初始化线程的 暂停/启动 信息处理,参考`章节9.1.1.2`
  if (SR_initialize() != 0) {
    perror("SR_initialize failed");
    return JNI_ERR;
  }
  // 继续系统级别的信号初始化,比如SIGSEGV、SIGBUS等
  Linux::signal_sets_init();
  // 给对应的信号安装/设置处理器程序
  Linux::install_signal_handlers();

  // 校验最小的线程栈大小,默认最小就是64k
  os::Linux::min_stack_allowed = MAX2(os::Linux::min_stack_allowed,
            (size_t)(StackYellowPages+StackRedPages+StackShadowPages) * Linux::page_size() +
                    (2*BytesPerWord COMPILER2_PRESENT(+1)) * Linux::vm_default_page_size());

  // 拿到默认设置/用户设置的ThreadStackSize
  size_t threadStackSizeInBytes = ThreadStackSize * K;
  // 比较,如果ThreadStackSize太小,就报错,退出
  if (threadStackSizeInBytes != 0 &&
      threadStackSizeInBytes < os::Linux::min_stack_allowed) {
        tty->print_cr("\nThe stack size specified is too small, "
                      "Specify at least %dk",
                      os::Linux::min_stack_allowed/ K);
        return JNI_ERR;
  }

  // 按大于threadStackSizeInBytes最近的2的幂次方设置
  JavaThread::set_stack_size_at_create(round_to(threadStackSizeInBytes,
        vm_page_size()));
  // 设置栈的范围(最高位和最低位)
  Linux::capture_initial_stack(JavaThread::stack_size_at_create());

#if defined(IA32) && !defined(ZERO)
  workaround_expand_exec_shield_cs_limit();
#endif

  Linux::libpthread_init();
  if (PrintMiscellaneous && (Verbose || WizardMode)) {
     tty->print_cr("[HotSpot is running with %s, %s(%s)]\n",
          Linux::glibc_version(), Linux::libpthread_version(),
          Linux::is_floating_stack() ? "floating stack" : "fixed stack");
  }
  // NUMA(Non-Uniform Memory Access)是一种计算机体系结构,为了学习hotspot源码方便,在保证原流程不影响的情况下,尽量减少一些其他的知识的参杂,这块就先忽略
  if (UseNUMA) {
    if (!Linux::libnuma_init()) {
      UseNUMA = false;
    } else {
      if ((Linux::numa_max_node() < 1)) {
        // There's only one node(they start from 0), disable NUMA.
        UseNUMA = false;
      }
    }
    // With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way
    // we can make the adaptive lgrp chunk resizing work. If the user specified
    // both UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn and
    // disable adaptive resizing.
    if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) {
      if (FLAG_IS_DEFAULT(UseNUMA)) {
        UseNUMA = false;
      } else {
        if (FLAG_IS_DEFAULT(UseLargePages) &&
            FLAG_IS_DEFAULT(UseSHM) &&
            FLAG_IS_DEFAULT(UseHugeTLBFS)) {
          UseLargePages = false;
        } else {
          warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing");
          UseAdaptiveSizePolicy = false;
          UseAdaptiveNUMAChunkSizing = false;
        }
      }
    }
    if (!UseNUMA && ForceNUMA) {
      UseNUMA = true;
    }
  }
 // 设置最大文件描述符限制
  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;
      status = setrlimit(RLIMIT_NOFILE, &nbr_files);
      if (status != 0) {
        if (PrintMiscellaneous && (Verbose || WizardMode))
          perror("os::init_2 setrlimit failed");
      }
    }
  }

  // 初始化创建线程时的锁在 os::create_thread 中会有
  Linux::set_createThread_lock(new Mutex(Mutex::leaf, "createThread_lock", false));

  if (PerfAllowAtExitRegistration) {
    if (atexit(perfMemory_exit_helper) != 0) {
      warning("os::init_2 atexit(perfMemory_exit_helper) failed");
    }
  }

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

  return JNI_OK;
}
9.1.1.2 SR_initialize
static int SR_initialize() {
  struct sigaction act;
  char *s;
  /* 通过环境变量 _JAVA_SR_SIGNUM 获取信号码 */
  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);

  // 设置信息处理器 SR_handler(产生信号时需要调用的函数)
  act.sa_flags = SA_RESTART|SA_SIGINFO;
  act.sa_handler = (void (*)(int)) SR_handler;

  // 获取信号屏蔽码
  pthread_sigmask(SIG_BLOCK, NULL, &act.sa_mask);
  // 给信号指定相关的处理程序
  if (sigaction(SR_signum, &act, 0) == -1) {
    return -1;
  }

  // 保存信号标志
  os::Linux::set_our_sigflags(SR_signum, act.sa_flags);
  return 0;
}
文章来源:https://blog.csdn.net/zhang527294844/article/details/135276529
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。