深入剖析创建Java虚拟机的实现方法
经过前文《深入剖析java.c文件中JavaMain方法中InitializeJVM的实现》的分析,找到了创建Java虚拟机具体实现的方法Threads::create_vm((JavaVMInitArgs*) args, &can_try_again)。该方法的实现在src\hotspot\share\runtime\threads.cpp文件,我去掉了部分英文注释和宏条件代码,代码更简洁清晰,下面我们看看该方法的具体细节:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | jint Threads::create_vm(JavaVMInitArgs* args, bool * canTryAgain) { // JDK版本信息初始化前的准备工作 extern void JDK_Version_init(); VM_Version::early_initialize(); // 检查版本是否支持 if (!is_supported_jni_version(args->version)) return JNI_EVERSION; // 初始化基于库的TLS(线程本地存储) ThreadLocalStorage::init(); // 初始化输出流模块 ostream_init(); // 处理Java启动器属性 Arguments::process_sun_java_launcher_properties(args); // 初始化操作系统模块,其中包括:获取进程ID、初始化系统信息、 // 设置流模式、设置虚拟内存页大小、初始化主进程句柄和主线程句柄等 os::init(); //该代码的作用是在MacOS AARCH64架构下启用当前线程的写执行保护 MACOS_AARCH64_ONLY(os::current_thread_enable_wx(WXWrite)); // 创建TraceVmCreationTime对象create_vm_timer,开始统计虚拟机创建时间 TraceVmCreationTime create_vm_timer; create_vm_timer.start(); // 初始化系统属性 Arguments::init_system_properties(); // 初始化JDK版本,以便在解析参数时使用 JDK_Version_init(); // 在JDK版本号已知后,更新或初始化系统属性 Arguments::init_version_specific_system_properties(); // 在解析参数之前,确保初始化日志配置 LogConfiguration::initialize(create_vm_timer.begin_time()); // 解析参数 jint parse_result = Arguments::parse(args); if (parse_result != JNI_OK) return parse_result; // 初始化内存跟踪 MemTracker::initialize(); // 初始化初始的活动处理器数量、大页面支持、栈溢出大小和VM版本 os::init_before_ergo(); // 设置堆大小,初始化元空间标志和对齐,设置编译器标志和 // 字节码重写标志,以及根据激进优化标志设置标志 jint ergo_result = Arguments::apply_ergo(); if (ergo_result != JNI_OK) return ergo_result; // 检查上述init_before_ergo()和apply_ergo()对JVM的设置 if (!JVMFlagLimit::check_all_ranges()) { return JNI_EINVAL; } // 检查上述init_before_ergo()和apply_ergo()对JVM的约束设置 bool constraint_result = JVMFlagLimit::check_all_constraints( JVMFlagConstraintPhase::AfterErgo); if (!constraint_result) { return JNI_EINVAL; } // 如果上述检查有问题,则暂停虚拟机初始化 if (PauseAtStartup) { os::pause(); } // 正式开始虚拟机的初始化 HOTSPOT_VM_INIT_BEGIN(); // 使用TraceTime计时器记录“Create VM”这个操作的时间,并将时间记录 // 在TRACETIME_LOG中的Info级别的startuptime日志中 TraceTime timer( "Create VM" , TRACETIME_LOG(Info, startuptime)); // 在全局参数解析后,初始化一些操作系统相关的设置, // 包括设置互斥锁初始化完成标志、配置Windows异常处理、 // 检查和设置最小堆栈大小、注册退出函数等 jint os_init_2_result = os::init_2(); if (os_init_2_result != JNI_OK) return os_init_2_result; // 初始化安全点机制 SafepointMechanism::initialize(); // 根据操作系统的结果进行调整 jint adjust_after_os_result = Arguments::adjust_after_os(); if (adjust_after_os_result != JNI_OK) return adjust_after_os_result; // 初始化输出流日志 ostream_init_log(); // 加载 -agentlib/-agentpath 和转化后的 -Xrun agents JvmtiAgentList::load_agents(); // 初始化线程状态 _number_of_threads = 0; _number_of_non_daemon_threads = 0; // 初始化虚拟机的全局变量,包括:基本类型、事件日志、 // 互斥锁、面向对象存储集、性能内存、可挂起线程集合等 vm_init_globals(); // 初始化Java线程的旧计数器,如果JVMCI计数器大小大于0, // 则会分配一个新的C堆数组来存储旧计数器,并将其初始化为0。 // 否则,将JavaThread::_jvmci_old_thread_counters设置为nullptr。 // 这段代码主要是为了支持JVMCI,该技术可以在运行时优化Java应用程序 #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 // 给当前线程对象初始化面向对象存储集 JavaThread::_thread_oop_storage = OopStorageSet::create_strong( "Thread OopStorage" , mtThread); // 创建一个JVM主线程,并将它挂载到当前操作系统线程上 JavaThread* main_thread = new JavaThread(); // 设置了线程的状态 main_thread->set_thread_state(_thread_in_vm); // 初始化JVM主线程 main_thread->initialize_thread_current(); // 记录了线程的栈基址和大小 before set_active_handles main_thread->record_stack_base_and_size(); // 将线程栈注册到NMT中 main_thread->register_thread_stack_with_NMT(); // 分配了一个JNIHandleBlock对象,为线程设置活动句柄 main_thread->set_active_handles(JNIHandleBlock::allocate_block()); // 在特定平台上对当前线程启用写保护 MACOS_AARCH64_ONLY(main_thread->init_wx()); // 以下if代码作用是:检查主线程是否被设置为起始线程, // 如果没有成功设置,则会发生内部分配失败,导致虚拟机初始化失败, // 此时会关闭虚拟机并返回错误代码JNI_ENOMEM 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 ; return JNI_ENOMEM; } // 在主线程创建后启用保护页,以避免Linux VM 崩溃 main_thread->stack_overflow_state()->create_stack_guard_pages(); // 初始化Java级别的同步子系统。首先调用ObjectMonitor类的 // Initialize方法来初始化监视器对象,然后调用ObjectSynchronizer // 类的initialize方法来初始化对象同步器。这些步骤是确保Java程序 // 中的多线程同步操作能够正确地执行 ObjectMonitor::Initialize(); ObjectSynchronizer::initialize(); // 初始化全局变量,包括:管理模块、对象存储、字节码、引导类加载器、 // 编译策略、代码缓存、虚拟机版本、存根、Java内存模型相关的组件 // (比如、TLAB、堆、元空间、方法缓存、方法表、符号表、字符串表、 // JVM内部数据结构等)以及GC日志、异步日志、垃圾回收栅栏、协程、 // 协程存根、解释器存根、访问标识、接口支持、寄存器名称、共享 // 运行时生成存根 jint status = init_globals(); if (status != JNI_OK) { // 删除主线程 main_thread->smr_delete(); // 将canTryAgain指针指向false,防止调用者再次调用 // JNI_CreateJavaVM函数 *canTryAgain = false ; return status; } // 将主线程添加到线程列表中,以完成栅栏的设置, // 并在init_globals2中构建Java对象之前进on_thread_attach。 // 该代码通过使用MutexLocker锁定线程锁Threads_lock, // 然后将主线程添加到线程列表中 { MutexLocker mu(Threads_lock); Threads::add(main_thread); } // 初始化一些全局变量 status = init_globals2(); if (status != JNI_OK) { // 从线程列表中移除指定的线程 Threads:: remove (main_thread, false ); main_thread->smr_delete(); *canTryAgain = false ; return status; } // 这段代码的作用是仅在JFR(Java Flight Recorder)启用时 // 调用Jfr::on_create_vm_1()函数 JFR_ONLY(Jfr::on_create_vm_1();) // 在堆完全创建后运行,主线程将缓存全局变量 main_thread->cache_global_variables(); // 在onload中进入的任何JVMTI原始监视器都将转换为真实的原始 // 监视器,在这里,VM已经设置好了,可以进入原始监视器 JvmtiExport::transition_pending_onload_raw_monitors(); // 以下代码的作用是创建一个虚拟机线程并等待它初始化完成 { 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." ); } { // 使用MonitorLocker和Notify_lock来等待VM线程初始化完成 MonitorLocker ml(Notify_lock); os::start_thread(vmthread); while (!vmthread->is_running()) { ml.wait(); } } } // Java内存模型及JVM核心组件是否初始化完成,确保我们以干净的状态开始 assert (Universe::is_fully_initialized(), "not initialized" ); if (VerifyDuringStartup) { VM_Verify verify_op; // 启动一个新线程,执行验证操作 VMThread::execute(&verify_op); } // 这段代码的作用是更新java.vm.info属性,以防初始定义 // 它的任何标志已被更改。 // 这对于CDS非常重要,因为UseSharedSpaces可能在java.vm.info // 最初计算之后被更改。在我们初始化java类之前,但在可能修改 // 标志的任何初始化逻辑之后,必须进行此更新。 // CDS是Class Data Sharing的缩写,是一种JVM的优化技术。 // 它可以将类数据预处理并保存在共享的归档文件中,以便在后续 // 的JVM启动中重用这些数据,从而加快JVM的启动时间 和内存占用。 // CDS在JDK 5中首次引入,JDK 8中进行了进一步的改进。 Arguments::update_vm_info_property(VM_Version::vm_info_string()); // 创建一个Java线程,并使用异常宏THREAD进行异常处理 JavaThread* THREAD = JavaThread::current(); // For exception macros. // 创建一个HandleMark对象,该对象在当前线程上下文中创建一个 // 句柄标记。这将确保在当前线程上下文中创建的所有句柄都被正确 // 处理,并在当前线程上下文结束时自动清除 HandleMark hm(THREAD); // 调用JvmtiExport的enter_early_start_phase()函数,即使还没有 // JVMTI环境,因为环境可能会晚些时候附加,JVMTI必须跟踪VM执行 // 的阶段,JvmtiExport是一个JVMTI API的导出类,其中包含了 // 许多用于与JVMTI代理交互的函数。 JvmtiExport::enter_early_start_phase(); // 通知JVMTI代理VM已经启动(JNI已经启动),如果没有代理则 // 不执行任何操作 JvmtiExport::post_early_vm_start(); // 检查是否设置了EagerXrunInit标志,如果设置了,则会尽早 // 启动-Xrun代理。 if (EagerXrunInit) { // 如果设置了该标志,则调用JvmtiAgentList::load_xrun_agents() // 函数来加载代理 JvmtiAgentList::load_xrun_agents(); } // 初始化Java核心java.lang包中的类,通过传入的主线程和检查 // JNI错误的参数来实现。 // 第1阶段:java.lang.系统类初始化。 // java.lang.System是一个原始类,由VM在启动初期加载和初始化。 // java.lang.System.<clinit>只执行registerNatives, // 并在线程初始化完成之前保留类初始化的其余工作。 // System.initPhase1初始化系统属性、静态字段in、out和err。 // 设置java信号处理程序、操作系统特定的系统设置和主线程的线程组。 initialize_java_lang_classes(main_thread, CHECK_JNI_ERR); // 加速JNI函数,通过使用快速版本替换获取基础类型的函数 quicken_jni_functions(); // 在这个点,存根代码不允许再生成了 // StubCodeDesc描述一段生成的代码(通常是存根)。此信息主要 // 用于调试和打印。目前代码描述符只是简单地链接在一个链表中, // 如果搜索变得太慢,这种情况可能不得不改变。 StubCodeDesc::freeze(); // 设置了一个标志,表示基本初始化已经完成。这个标志被异常和 // 各种调试工具使用,在所有基本类都被初始化之前无法使用 set_init_completed(); // 下面三行代码分别调用了三个类的post_initialize()函数。 // 其中LogConfiguration类用于配置日志输出, // Metaspace类用于管理元空间, // MutexLocker类用于管理锁。 // 这些函数的作用是在程序启动后初始化相关的资源和状态,以便 // 后续的程序运行。每个类的post_initialize()函数都会执行一些 // 初始化操作,例如设置默认值、分配内存等。这样可以确保程序在 // 正式运行前已经准备好了必要的资源和状态,从而提高程序的 // 稳定性和性能 LogConfiguration::post_initialize(); Metaspace::post_initialize(); MutexLocker::post_initialize(); // Java虚拟机初始化完成 HOTSPOT_VM_INIT_END(); // 如果包含管理功能,则调用Management类的 // record_vm_init_completed()方法记录虚拟机初始化完成的时间 #if INCLUDE_MANAGEMENT Management::record_vm_init_completed(); #endif // INCLUDE_MANAGEMENT // 打印初始化JVM的进程ID log_info(os)( "Initialized VM with process ID %d" , os::current_process_id()); // 在VMInit事件被发布之前启动Signal Dispatcher os::initialize_jdk_signal_support(CHECK_JNI_ERR); // AttachListener线程通过客户端工具为排队的操作队列提供服务。 // 每个操作都由一个名称标识,最多有3个参数。 // 操作名称映射到执行操作的函数,被outputStream调用, // 该输出流可用于写入任何结果数据(例如,序列化写入properties // 名称和值)当该函数执行完成,会将所有结果数据返回给客户端工具 if (!DisableAttachMechanism) { // 如果没有禁用Attach 机制,则启动AttachListener。 AttachListener::vm_start(); if (StartAttachListener || AttachListener::init_at_startup()) { AttachListener::init(); } } // 如果没有设置EagerXrunInit,则启动-Xrun代理 if (!EagerXrunInit) { JvmtiAgentList::load_xrun_agents(); } // 启动一个清理内存池的任务 Chunk::start_chunk_pool_cleaner_task(); // JVMTI是Java虚拟机工具接口(Java Virtual Machine Tool Interface) // 的缩写。它是一组用于Java虚拟机的原生编程接口,允许开发人员 // 创建各种工具来监视、管理和分析Java应用程序的行为。JVMTI提供了 // 对Java虚拟机内部状态的访问,包括类、对象、线程和堆信息等。 // 它还允许开发人员创建自己的代理程序,以便在Java应用程序中动态 // 植入代码。JVMTI常用于Java应用程序的性能分析、调试和测试等方面。 // 启动了一个服务线程,该服务线程将JVMTI延迟事件排队,并进行 // 各种哈希表和其他清理工作。需要在编译器开始发布事件之前启动。 ServiceThread::initialize(); // 启动了监视器缩减线程。首先,代码调用了MonitorDeflationThread // 类的initialize()方法。这个方法可能会执行一些初始化操作,然后 // 启动一个后台线程,该线程会定期检查系统中的监视器,以确保它们 // 不会占用太多的内存。如果监视器过大,线程会自动将其缩小。 // 这个线程将在后台运行,直到系统关闭或线程被显式停止。 MonitorDeflationThread::initialize(); // 以下宏条件中的代码,意思是初始化编译器 // JVMCI是Java虚拟机编译接口(JVM Compiler Interface)的缩写, // 它是Java 9引入的一个新的JIT编译器接口。JVMCI允许第三方开发者 // 编写JIT编译器,并将其集成到Java虚拟机中,以替代默认的JIT编译 // 器。JVMCI的引入使得Java虚拟机更加灵活,可以根据具体的应用 // 场景选择更加适合的JIT编译器,从而提高Java应用程序的性能。 #if defined(COMPILER1) || COMPILER2_OR_JVMCI #if INCLUDE_JVMCI bool force_JVMCI_intialization = false ; if (EnableJVMCI) { // 在初始化JVMCI时,如果启用了EagerJVMCI或者 // JVMCIPrintProperties或者JVMCILibDumpJNIConfig, // 则强制初始化JVMCI。否则,如果使用了JVMCI编译器 // 并且不使用解释器或后台编译,则强制初始化JVMCI force_JVMCI_intialization = EagerJVMCI || JVMCIPrintProperties || JVMCILibDumpJNIConfig; if (!force_JVMCI_intialization) { force_JVMCI_intialization = UseJVMCICompiler && (!UseInterpreter || !BackgroundCompilation); } } #endif CompileBroker::compilation_init_phase1(CHECK_JNI_ERR); if (JVMCI_ONLY(!force_JVMCI_intialization) NOT_JVMCI( true )) { CompileBroker::compilation_init_phase2(); } #endif // 如果启用了字符串去重功能,则启动字符串去重线程 if (StringDedup::is_enabled()) { StringDedup::start(); } // 预初始化一些JSR292核心类,以避免在类加载期间发生死锁。 // 它在编译器初始化后执行,因为否则可能会错过签名多态 // MH内部函数的编译。方法内部代码步骤: // 1. 初始化java.lang包中类的方法处理的调用。 // 2. 初始化java.lang包中类的解析方法名称的调用。 // 3. 初始化java.lang包中类的成员名称的调用。 // 4. 初始化java.lang包中类的本地方法处理的调用。 initialize_jsr292_core_classes(CHECK_JNI_ERR); // 第2阶段初始化:初始化模块系统,并且只有在第二阶段完成之前 // 可以加载java.base类。在编译器初始化和jsr292类初始化 // System.initPhase2,因为模块初始化运行了大量java代码,出于 // 性能原因,应该编译这些代码。此外,这将使启动代码能够在此 // 阶段及以后使用lambda和其他语言功能。在第2阶段之后, // 虚拟机将从-Xbootclasspath/a开始搜索类。 call_initPhase2(CHECK_JNI_ERR); // 只有在启用了JFR(Java Flight Recorder)时才会执行该函数。 // JFR是一种用于收集和分析Java应用程序性能数据的工具 JFR_ONLY(Jfr::on_create_vm_2();) // 即使没有JVMTI环境也要调用,因为环境可能会在后期附加, // JVMTI必须跟踪VM执行阶段。 JvmtiExport::enter_start_phase(); // 通知JVMTI代理VM已经启动(JNI已经启动), // 如果没有代理则不执行任何操作。 JvmtiExport::post_vm_start(); // 第3阶段初始化 最后设置安全管理器、系统类加载器和TCCL。这将 // 实例化和设置安全管理器,设置系统类加载器以及线程上下文类 // 加载器。安全管理器和系统类加载器可以是从-Xbootclasspath/a、 // 其他模块或应用程序的类路径加载的自定义类。 call_initPhase3(CHECK_JNI_ERR); // 这段代码的作用是缓存系统和平台类加载器。在该方法中,首先, // 通过调用ClassLoader类的getSystemClassLoader方法和 // getPlatformClassLoader方法获取系统类加载器和平台类加载器, // 并将其缓存起来 SystemDictionary::compute_java_loaders(CHECK_JNI_ERR); // 如果定义了INCLUDE_CDS宏,则初始化类加载器的模块路径信息。 // 如果在初始化过程中出现异常,则会打印异常信息并退出虚拟机。 #if INCLUDE_CDS 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 // 在JVMCI被包含的情况下,如果需要强制初始化JVMCI, // 则进行编译器的初始化,并执行编译初始化的第二阶段 #if INCLUDE_JVMCI if (force_JVMCI_intialization) { JVMCI::initialize_compiler(CHECK_JNI_ERR); CompileBroker::compilation_init_phase2(); } #endif // 方法是JVMTI API的一部分,用于通知JVMTI环境进入VM的“live”阶段, // 即VM正在运行并且可以被监视和分析。这个方法应该在VM启动后尽早 // 调用,因为JVMTI需要跟踪VM执行的不同阶段。如果JVMTI环境在后期 // 附加,这个方法也应该被调用,以确保JVMTI能够正确跟踪VM的状态 JvmtiExport::enter_live_phase(); // 使性能内存可访问 // 性能内存通常用于存储程序运行时的性能数据,如CPU使用率、 // 内存使用率等。通过使性能内存可访问,开发人员可以获取这些数据 // 并进行分析,以便优化程序的性能。 PerfMemory::set_accessible( true ); // 通知JVMTI代理VM初始化完成,如果没有代理则不执行任何操作 JvmtiExport::post_vm_initialized(); // 在启用JFR时,当虚拟机被创建时记录其配置信息。 JFR_ONLY(Jfr::on_create_vm_3();) // 如果定义了INCLUDE_MANAGEMENT宏,则初始化类管理器, // 如果有异常,则退出VM。 #if INCLUDE_MANAGEMENT Management::initialize(THREAD); if (HAS_PENDING_EXCEPTION) { vm_exit(1); } #endif // 调用统计采样器(StatSampler) StatSampler::engage(); if (CheckJNICalls) JniPeriodicChecker::engage(); // 如果定义了INCLUDE_RTM_OPT宏,则初始化用于计数的锁,它允许 // 多个线程同时访问计数器,并确保计数器的值正确地增加或减少。 #if INCLUDE_RTM_OPT RTMLockingCounters::init(); #endif // 调用VM初始化完成后的钩子方法,Java库方法本身可以独立于VM进行更改 call_postVMInitHook(THREAD); // 在PostVMInitHook.run方法的Java部分处理所有异常并提供诊断手段。 // 如果存在挂起异常,则清除挂起异常。. if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; } // 启动一个WatcherThread线程来执行周期性任务 { // 通过MutexLocker来锁定PeriodicTask_lock,确保WatcherThread // 可以通过WatcherThread::start()或动态注册来启动 MutexLocker ml(PeriodicTask_lock); // 将WatcherThread设置为可启动状态 WatcherThread::make_startable(); // 如果有周期性任务,则启动WatcherThread线程来执行任务。 // 需要注意的是,所有的周期性任务应该在此之前都已经注册了, // 否则晚注册的任务可能会启动缓慢。 if (PeriodicTask::num_tasks() > 0) { WatcherThread::start(); } } // 结束创建虚拟机的计时器计时 create_vm_timer.end(); #ifdef ASSERT _vm_complete = true ; #endif // 判断是否启用了DumpSharedSpaces选项,如果启用, // 则调用MetaspaceShared::preload_and_dump()函数, // 该函数的作用是预加载和转储共享空间。然后,代码调用 // ShouldNotReachHere()函数,该函数的作用是抛出一个错误, // 表示代码执行到了不应该到达的地方。 if (DumpSharedSpaces) { MetaspaceShared::preload_and_dump(); ShouldNotReachHere(); } return JNI_OK; } |
下面用一张流程图概括:

如果您觉得博文不错,请用微信扫描右上方二维码,关注我的微信公众号“编程老司机”,获取最新推送文章。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端