这个函数是在全部参数都解析后调用的
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;
}
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;
}