在JLI_Launch方法种就有jvm初始化
jboolean
LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
{
void *libjvm;
JLI_TraceLauncher("JVM path is %s\n", jvmpath);
libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
if (libjvm == NULL) {
JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
return JNI_FALSE;
}
ifn->CreateJavaVM = (CreateJavaVM_t)
dlsym(libjvm, "JNI_CreateJavaVM");
if (ifn->CreateJavaVM == NULL) {
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
return JNI_FALSE;
}
ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
if (ifn->GetDefaultJavaVMInitArgs == NULL) {
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
return JNI_FALSE;
}
ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
dlsym(libjvm, "JNI_GetCreatedJavaVMs");
if (ifn->GetCreatedJavaVMs == NULL) {
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
return JNI_FALSE;
}
return JNI_TRUE;
}
ifn->CreateJavaVM 从jvm库文件获取对应的方法链接
在新线程执行方法JavaMain才会调用到库文件中的方法
if (!InitializeJVM(&vm, &env, &ifn)) {
JLI_ReportErrorMessage(JVM_ERROR1);
exit(1);
}
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;
if (JLI_IsTraceLauncher()) {
int i = 0;
printf("JavaVM args:\n ");
printf("version 0x%08lx, ", (long)args.version);
printf("ignoreUnrecognized is %s, ",
args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE");
printf("nOptions is %ld\n", (long)args.nOptions);
for (i = 0; i < numOptions; i++)
printf(" option[%2d] = '%s'\n",
i, args.options[i].optionString);
}
r = ifn->CreateJavaVM(pvm, (void **)penv, &args);
JLI_MemFree(options);
return r == JNI_OK;
}
看一下具体调用
该方法可以找到CreateJavaVM_t实际连接的是JNI_CreateJavaVM
jni的部分可以在jni.cpp中查看到
JNI_IMPORT_OR_EXPORT jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args)
其调用的方法是
result = JNI_CreateJavaVM_inner(vm, penv, args);
static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) {
HOTSPOT_JNI_CREATEJAVAVM_ENTRY((void **) vm, penv, args);
jint result = JNI_ERR;
DT_RETURN_MARK(CreateJavaVM, jint, (const jint&)result);
if (Atomic::xchg(&vm_created, IN_PROGRESS) != NOT_CREATED) {
return JNI_EEXIST; // already created, or create attempt in progress
}
if (Atomic::xchg(&safe_to_recreate_vm, 0) == 0) {
return JNI_ERR;
}
bool can_try_again = true;
//在线程中创建jvm
result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again);
if (result == JNI_OK) {
JavaThread *thread = JavaThread::current();
assert(!thread->has_pending_exception(), "should have returned not OK");
// thread is thread_in_vm here
//将引用赋值JavaVM,用于创建后其他线程调用
*vm = (JavaVM *)(&main_vm);
//暴露环境给外部使用
*(JNIEnv**)penv = thread->jni_environment();
// mark creation complete for other JNI ops
Atomic::release_store(&vm_created, COMPLETE);
//jvmci及时编译器功能在jdk10以后出现的,在创建虚拟机后将编译器添加到一个线程上面
#if INCLUDE_JVMCI
if (EnableJVMCI) {
if (UseJVMCICompiler) {
// JVMCI is initialized on a CompilerThread
if (BootstrapJVMCI) {
JavaThread* THREAD = thread; // For exception macros.
JVMCICompiler* compiler = JVMCICompiler::instance(true, CATCH);
compiler->bootstrap(THREAD);
if (HAS_PENDING_EXCEPTION) {
HandleMark hm(THREAD);
vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
}
}
}
}
#endif
//jvmti作为事件监听器
// Notify JVMTI
if (JvmtiExport::should_post_thread_life()) {
JvmtiExport::post_thread_start(thread);
}
JFR_ONLY(Jfr::on_thread_start(thread);)
if (ReplayCompiles) ciReplay::replay(thread);
#ifdef ASSERT
// Some platforms (like Win*) need a wrapper around these test
// functions in order to properly handle error conditions.
if (ErrorHandlerTest != 0) {
VMError::controlled_crash(ErrorHandlerTest);
}
#endif
// Since this is not a JVM_ENTRY we have to set the thread state manually before leaving.
ThreadStateTransition::transition_from_vm(thread, _thread_in_native);
MACOS_AARCH64_ONLY(thread->enable_wx(WXExec));
} else {
// If create_vm exits because of a pending exception, exit with that
// exception. In the future when we figure out how to reclaim memory,
// we may be able to exit with JNI_ERR and allow the calling application
// to continue.
if (Universe::is_fully_initialized()) {
// otherwise no pending exception possible - VM will already have aborted
Thread* current = Thread::current_or_null();
if (current != nullptr) {
JavaThread* THREAD = JavaThread::cast(current); // For exception macros.
assert(HAS_PENDING_EXCEPTION, "must be - else no current thread exists");
HandleMark hm(THREAD);
vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
}
}
if (can_try_again) {
// reset safe_to_recreate_vm to 1 so that retrial would be possible
safe_to_recreate_vm = 1;
}
// Creation failed. We must reset vm_created
*vm = 0;
*(JNIEnv**)penv = 0;
// reset vm_created last to avoid race condition. Use OrderAccess to
// control both compiler and architectural-based reordering.
assert(vm_created == IN_PROGRESS, "must be");
Atomic::release_store(&vm_created, NOT_CREATED);
}
// Flush stdout and stderr before exit.
fflush(stdout);
fflush(stderr);
return result;
}
可以看出创建虚拟机没有新建线程,直接进行的初始化,继续看代码,
create_vm就是虚拟机创建的主方法,在方法里面进行了虚拟机参数的加载,系统的初始化比如动态链接库加载,gc参数加载等
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
extern void JDK_Version_init();
// Preinitialize version info.
VM_Version::early_initialize();
// Check version
if (!is_supported_jni_version(args->version)) return JNI_EVERSION;
// Initialize library-based TLS
//调用系统开辟当前线程的threadlocal的空间
ThreadLocalStorage::init();
// Initialize the output stream module
//虚拟机系统输出初始化
ostream_init();
// Process java launcher properties.
Arguments::process_sun_java_launcher_properties(args);
// Initialize the os module
//决定当前操作系统的API,获取操作系统分页大小设置到虚拟机,并且拿到时钟
os::init();
MACOS_AARCH64_ONLY(os::current_thread_enable_wx(WXWrite));
// Record VM creation timing statistics
TraceVmCreationTime create_vm_timer;
create_vm_timer.start();
// Initialize system properties.
//初始化系统参数,比如路径set_boot_path将modules设置完成
Arguments::init_system_properties();
// So that JDK version can be used as a discriminator when parsing arguments
JDK_Version_init();
// Update/Initialize System properties after JDK version number is known
Arguments::init_version_specific_system_properties();
// Make sure to initialize log configuration *before* parsing arguments
LogConfiguration::initialize(create_vm_timer.begin_time());
// Parse arguments
// Note: this internally calls os::init_container_support()
jint parse_result = Arguments::parse(args);
if (parse_result != JNI_OK) return parse_result;
// Initialize NMT right after argument parsing to keep the pre-NMT-init window small.
//内存追踪NMT,开启后jcmd可以获取内存分布情况
MemTracker::initialize();
//初始化处理器,内存大分页参数(最小的分页大小,提升性能用的),内存保护区域参数(内存用到这里很危险)
os::init_before_ergo();
//设置虚拟机的内存参数
jint ergo_result = Arguments::apply_ergo();
if (ergo_result != JNI_OK) return ergo_result;
// Final check of all ranges after ergonomics which may change values.
if (!JVMFlagLimit::check_all_ranges()) {
return JNI_EINVAL;
}
// Final check of all 'AfterErgo' constraints after ergonomics which may change values.
bool constraint_result = JVMFlagLimit::check_all_constraints(JVMFlagConstraintPhase::AfterErgo);
if (!constraint_result) {
return JNI_EINVAL;
}
if (PauseAtStartup) {
os::pause();
}
HOTSPOT_VM_INIT_BEGIN();
// Timing (must come after argument parsing)
TraceTime timer("Create VM", TRACETIME_LOG(Info, startuptime));
// Initialize the os module after parsing the args
jint os_init_2_result = os::init_2();
if (os_init_2_result != JNI_OK) return os_init_2_result;
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
// Initialize assert poison page mechanism.
if (ShowRegistersOnAssert) {
initialize_assert_poison();
}
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
//安全点pollingpage等参数设置
SafepointMechanism::initialize();
//如果是多cpu支持numa则设置并行的gc
jint adjust_after_os_result = Arguments::adjust_after_os();
if (adjust_after_os_result != JNI_OK) return adjust_after_os_result;
// Initialize output stream logging
//ClassListWriter初始化,这个是APPCDS用于提升加载速度的
ostream_init_log();
// Launch -agentlib/-agentpath and converted -Xrun agents
JvmtiAgentList::load_agents();
// Initialize Threads state
_number_of_threads = 0;
_number_of_non_daemon_threads = 0;
// Initialize global data structures and create system classes in heap
//字面上在堆里初始化全局数据结构
vm_init_globals();
#if INCLUDE_JVMCI
if (JVMCICounterSize > 0) {
JavaThread::_jvmci_old_thread_counters = NEW_C_HEAP_ARRAY(jlong, JVMCICounterSize, mtJVMCI);
memset(JavaThread::_jvmci_old_thread_counters, 0, sizeof(jlong) * JVMCICounterSize);
} else {
JavaThread::_jvmci_old_thread_counters = nullptr;
}
#endif // INCLUDE_JVMCI
// Initialize OopStorage for threadObj
JavaThread::_thread_oop_storage = OopStorageSet::create_strong("Thread OopStorage", mtThread);
// Attach the main thread to this os thread
JavaThread* main_thread = new JavaThread();
main_thread->set_thread_state(_thread_in_vm);
main_thread->initialize_thread_current();
// must do this before set_active_handles
main_thread->record_stack_base_and_size();
main_thread->register_thread_stack_with_NMT();
main_thread->set_active_handles(JNIHandleBlock::allocate_block());
MACOS_AARCH64_ONLY(main_thread->init_wx());
if (!main_thread->set_as_starting_thread()) {
vm_shutdown_during_initialization(
"Failed necessary internal allocation. Out of swap space");
main_thread->smr_delete();
*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->stack_overflow_state()->create_stack_guard_pages();
// Initialize Java-Level synchronization subsystem
//c++中多线程相关初始化,synchronized关键字相关初始化,两个都跟java锁相关
ObjectMonitor::Initialize();
ObjectSynchronizer::initialize();
// Initialize global modules
//其中的classLoader_init1()加载了dll库,后面jni会用 universe_init()初始化了gc配置以及堆空间
jint status = init_globals();
if (status != JNI_OK) {
main_thread->smr_delete();
*canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
return status;
}
// Create WatcherThread as soon as we can since we need it in case
// of hangs during error reporting.
WatcherThread::start();
// Add main_thread to threads list to finish barrier setup with
// on_thread_attach. Should be before starting to build Java objects in
// init_globals2, which invokes barriers.
{
MutexLocker mu(Threads_lock);
Threads::add(main_thread);
}
status = init_globals2();
if (status != JNI_OK) {
Threads::remove(main_thread, false);
// It is possible that we managed to fully initialize Universe but have then
// failed by throwing an exception. In that case our caller JNI_CreateJavaVM
// will want to report it, so we can't delete the main thread.
if (!main_thread->has_pending_exception()) {
main_thread->smr_delete();
}
*canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
return status;
}
JFR_ONLY(Jfr::on_create_vm_1();)
// Should be done after the heap is fully created
main_thread->cache_global_variables();
// 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", TRACETIME_LOG(Info, startuptime));
VMThread::create();
VMThread* vmthread = VMThread::vm_thread();
if (!os::create_thread(vmthread, os::vm_thread)) {
vm_exit_during_initialization("Cannot create VM thread. "
"Out of system resources.");
}
// Wait for the VM thread to become ready, and VMThread::run to initialize
// Monitors can have spurious returns, must always check another state flag
{
MonitorLocker ml(Notify_lock);
os::start_thread(vmthread);
while (!vmthread->is_running()) {
ml.wait();
}
}
}
assert(Universe::is_fully_initialized(), "not initialized");
if (VerifyDuringStartup) {
// Make sure we're starting with a clean slate.
VM_Verify verify_op;
VMThread::execute(&verify_op);
}
// We need this to update the java.vm.info property in case any flags used
// to initially define it have been changed. This is needed for both CDS
// since UseSharedSpaces may be changed after java.vm.info
// is initially computed. See Abstract_VM_Version::vm_info_string().
// This update must happen before we initialize the java classes, but
// after any initialization logic that might modify the flags.
Arguments::update_vm_info_property(VM_Version::vm_info_string());
JavaThread* THREAD = JavaThread::current(); // For exception macros.
HandleMark hm(THREAD);
// 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_early_start_phase();
// Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.
JvmtiExport::post_early_vm_start();
// Launch -Xrun agents early if EagerXrunInit is set
if (EagerXrunInit) {
JvmtiAgentList::load_xrun_agents();
}
//初始化java lang包的class
initialize_java_lang_classes(main_thread, CHECK_JNI_ERR);
quicken_jni_functions();
// No more stub generation allowed after that point.
StubCodeDesc::freeze();
// 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();
LogConfiguration::post_initialize();
Metaspace::post_initialize();
MutexLocker::post_initialize();
HOTSPOT_VM_INIT_END();
// record VM initialization completion time
#if INCLUDE_MANAGEMENT
Management::record_vm_init_completed();
#endif // INCLUDE_MANAGEMENT
log_info(os)("Initialized VM with process ID %d", os::current_process_id());
// Signal Dispatcher needs to be started before VMInit event is posted
os::initialize_jdk_signal_support(CHECK_JNI_ERR);
// Start Attach Listener if +StartAttachListener or it can't be started lazily
if (!DisableAttachMechanism) {
AttachListener::vm_start();
if (StartAttachListener || AttachListener::init_at_startup()) {
AttachListener::init();
}
}
// Launch -Xrun agents if EagerXrunInit is not set.
if (!EagerXrunInit) {
JvmtiAgentList::load_xrun_agents();
}
Chunk::start_chunk_pool_cleaner_task();
// Start the service thread
// The service thread enqueues JVMTI deferred events and does various hashtable
// and other cleanups. Needs to start before the compilers start posting events.
ServiceThread::initialize();
// Start the monitor deflation thread:
MonitorDeflationThread::initialize();
// initialize compiler(s)
#if defined(COMPILER1) || COMPILER2_OR_JVMCI
#if INCLUDE_JVMCI
bool force_JVMCI_intialization = false;
if (EnableJVMCI) {
// Initialize JVMCI eagerly when it is explicitly requested.
// Or when JVMCILibDumpJNIConfig or JVMCIPrintProperties is enabled.
force_JVMCI_intialization = EagerJVMCI || JVMCIPrintProperties || JVMCILibDumpJNIConfig;
if (!force_JVMCI_intialization) {
// 8145270: Force initialization of JVMCI runtime otherwise requests for blocking
// compilations via JVMCI will not actually block until JVMCI is initialized.
force_JVMCI_intialization = UseJVMCICompiler && (!UseInterpreter || !BackgroundCompilation);
}
}
#endif
//初始化jit,方法中会判断系统是否启用,是才会启动新的线程
CompileBroker::compilation_init_phase1(CHECK_JNI_ERR);
// Postpone completion of compiler initialization to after JVMCI
// is initialized to avoid timeouts of blocking compilations.
if (JVMCI_ONLY(!force_JVMCI_intialization) NOT_JVMCI(true)) {
CompileBroker::compilation_init_phase2();
}
#endif
// Start string deduplication thread if requested.
if (StringDedup::is_enabled()) {
StringDedup::start();
}
// 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_jsr292_core_classes(CHECK_JNI_ERR);
// This will initialize the module system. Only java.base classes can be
// loaded until phase 2 completes
call_initPhase2(CHECK_JNI_ERR);
JFR_ONLY(Jfr::on_create_vm_2();)
// 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();
// Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.
JvmtiExport::post_vm_start();
// Final system initialization including security manager and system class loader
call_initPhase3(CHECK_JNI_ERR);
// cache the system and platform class loaders
SystemDictionary::compute_java_loaders(CHECK_JNI_ERR);
#if INCLUDE_CDS
// capture the module path info from the ModuleEntryTable
ClassLoader::initialize_module_path(THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, tty);
vm_exit_during_initialization("ClassLoader::initialize_module_path() failed unexpectedly");
}
#endif
#if INCLUDE_JVMCI
if (force_JVMCI_intialization) {
JVMCI::initialize_compiler(CHECK_JNI_ERR);
CompileBroker::compilation_init_phase2();
}
#endif
// 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_live_phase();
// Make perfmemory accessible
PerfMemory::set_accessible(true);
// Notify JVMTI agents that VM initialization is complete - nop if no agents.
JvmtiExport::post_vm_initialized();
JFR_ONLY(Jfr::on_create_vm_3();)
#if INCLUDE_MANAGEMENT
Management::initialize(THREAD);
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);
}
#endif // INCLUDE_MANAGEMENT
StatSampler::engage();
if (CheckJNICalls) JniPeriodicChecker::engage();
#if INCLUDE_RTM_OPT
RTMLockingCounters::init();
#endif
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;
}
// Let WatcherThread run all registered periodic tasks now.
// 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).
WatcherThread::run_all_tasks();
create_vm_timer.end();
#ifdef ASSERT
_vm_complete = true;
#endif
if (DumpSharedSpaces) {
MetaspaceShared::preload_and_dump();
ShouldNotReachHere();
}
return JNI_OK;
}