JVM是如何执行Java方法的
2024-11-28 20:26:20 0 举报
AI智能生成
Java虚拟机(JVM)是执行Java字节码的引擎。当Java程序被执行时,首先被编译为字节码文件(.class文件)。然后,JVM通过类加载器(ClassLoader)将字节码文件加载到内存中,解释或编译为机器代码。在执行过程中,JVM使用运行时数据区(Runtime Data Area)来存储程序运行所需的数据,如堆(Heap)、栈(Stack)、方法区(Method Area)等。JVM还包含执行引擎,负责解析字节码,执行机器代码,从而完成程序的运行。JVM通过垃圾回收器(Garbage Collector)来管理内存,确保程序运行的稳定性和性能。
作者其他创作
大纲/内容
jvm是分为两部分,jdk和HotSpot,我们一般写的程序是从JDK开始启动,HotSpot源码对于jdk来说就是一个lib库,libjvm.so
HotSpot这个项目只有一个main方法。它位于/jdk/src/share/bin/main.c
HotSpot这个项目只有一个main方法。它位于/jdk/src/share/bin/main.c
接着会走到JLI_Launch方法,该方法会设置一系列的系统属性,关键的方法在JVMInit
LoadJavaVM方法中给ifn成员属性赋值
ifn的createVM成员赋值,JNI_CreateJavaVM
设置classPath
处理AddOption参数
Xss/Xmx/Xms在这里处理
处理启动参数
如果是-jar 启动则重写classpath
JVMInit方法中调用了ContinueInNewThread
如果通过-Xss配置了就取配置的参数,没有就取默认的参数,这个参数呢是从ifn结构体里面取得
我们需要找到ifn赋值的地方看看这个取出来的默认值是多少,单位是K
我们需要找到ifn赋值的地方看看这个取出来的默认值是多少,单位是K
ifnd的GetDefaultJavaVMInitArgs属性是通过JNI_GetDefaultJavaVMInitArgs这个方法拿到的
里面又调用了ContinueInNewThread0方法
接着又通过pthread_create创建出一个main线程,然后join阻塞住,注意,这个main线程是JVM的主线程,
不是程序的主线程,程序主线程在创建完JVM的主线程之后他就会阻塞,接着JVM主线程执行线程执行函数JavaMain
不是程序的主线程,程序主线程在创建完JVM的主线程之后他就会阻塞,接着JVM主线程执行线程执行函数JavaMain
这里传入的JavaMain是一个entry point,它是一个线程执行函数
这里的JavaMain里面,会调用InitializeJVM进行初始化。初始化JVM完之后,还会调用LoadMainClass加载main方法
这里是调用到了JNI的CreateJavaVM方法,
再通过Threads::createVM把JVM创建出来
那么Threads::createVM做了哪些事情呢?
osstream_init做了输出流的赋值
通过defaultStream::instance赋值,
并且通过tty-time_stamp().update_to(1);更新了时间戳
通过defaultStream::instance赋值,
并且通过tty-time_stamp().update_to(1);更新了时间戳
os::init
在使用TLS之前进行一些OS的初始化工作
在使用TLS之前进行一些OS的初始化工作
Argumentes::init_system_properties这里涉及了一些jvm的一些基本系统属性,像JVM的版本号,以及jvm的classpath路径等等
JDK_Version_init()JVM的版本号初始化,major和minor
Arguments:init_version_specific_system_properties,在知道JVM的版本号之后,更新一些系统属性
Arguments::parse
解析-XX:+PrintVMOptions/-XX:+IgnoreUnrecognizedVMOptions类似的参数
解析-XX:+PrintVMOptions/-XX:+IgnoreUnrecognizedVMOptions类似的参数
os::init_before_ergo
Argument::apply_ergo
set_ergonomics_flags()
这里会走到os::is_server_class_machine()
这里会走到os::is_server_class_machine()
set_ergonomics_flags()方法再往下走
Arguments::set_use_compressed_oops()
这里会设置JVM的Flag参数取决于是否使用了压缩技术
接着还会调用set_use_compressed_klass_ptrs()
Arguments::set_use_compressed_oops()
这里会设置JVM的Flag参数取决于是否使用了压缩技术
接着还会调用set_use_compressed_klass_ptrs()
set_shared_spaces_flags()
ArgumentsExt::check_gc_consistency_ergo()
最终会走到check_gclog_consistency
检查用户设置的收集器是否冲突
检查用户设置的收集器是否冲突
Arguments::set_heap_size.根据可用的物理机器内存设置堆空间大小
初始化元空间的标志和对齐
Arguments::set_bytecode_flags(),设置字节码相关的flag标志
Arguments::set_aggressive_opts_flags
if (PauseAtStartup) {
os::pause();
}
os::pause();
}
启动JVM计时器
create_vm_timer.start();
create_vm_timer.start();
os::init_2,在解析完参数之后,初始化os相关模块
fast_thread_clock_init()初始化线程时钟
os::set_polling_page()分配一个页面并将其标记为可读以便安全点轮询
os::Linux::signal_sets_init():初始化信号处理
os::Linux::install_signal_handlers():安装操作系统信号处理器
os::Linux::install_signal_handlers():安装操作系统信号处理器
Arguments::adjust_after_os()
ThreadLocalStorage::init();TLS类似ThreadLocal
pd_init(),验证下vm_page_size()
os::allocate_thread_local_storage()
key一旦被创建,所有线程都可以访问它,单个线程可根据自己的需要往key中填入不同的值,
这就相当于提供了一个同名而不通知的全局变量,一键多值
key一旦被创建,所有线程都可以访问它,单个线程可根据自己的需要往key中填入不同的值,
这就相当于提供了一个同名而不通知的全局变量,一键多值
set_thread_index()
generate_code_for_get_thread()是一个空方法
ostream_init_log(),初始化输出日志相关
vm_init_globals()创建全局数据结构并在堆中创建系统类
check_ThreadShadow()
basic_types_init()验证基本数据类型所占用的字节数是否正确
eventlog_init()
mutex_init()使用了Mutex的锁初始化
chunkpool_init()内存池的初始化
PerfMemory::initialize() 初始化perfMemory
// Attach the main thread to this os thread
JavaThread* main_thread = new JavaThread();
将主线程附着在这个os线程上
JavaThread* main_thread = new JavaThread();
将主线程附着在这个os线程上
// Initialize Java-Level synchronization subsystem
ObjectMonitor::Initialize() ;
初始化Java级别同步子系统
ObjectMonitor::Initialize() ;
初始化Java级别同步子系统
// Initialize global modules
jint status = init_globals();
jint status = init_globals();
management_init();
void bytecodes_init() {
Bytecodes::initialize();
}
初始化字节码指令
Bytecodes::initialize();
}
初始化字节码指令
void classLoader_init() {
ClassLoader::initialize();
}
ClassLoader::initialize();
}
void codeCache_init() {
CodeCache::initialize();
}
初始化代码缓存空间
CodeCache::initialize();
}
初始化代码缓存空间
void VM_Version_init() {
VM_Version::initialize();
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
os::print_cpu_info(tty);
}
#endif
}
VM_Version::initialize();
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
os::print_cpu_info(tty);
}
#endif
}
os_init_globals()
void stubRoutines_init1() { StubRoutines::initialize1(); }
universe_init()
Universe::initialize_heap()
interpreter_init()
invocationCounter_init()
marksweep_init()
accessFlags_init()
void templateTable_init() {
TemplateTable::initialize();
}
这里会初始化每条字节码指令对应的执行流
TemplateTable::initialize();
}
这里会初始化每条字节码指令对应的执行流
例如,_new指令对应的执行流
InterfaceSupport_init()
SharedRuntime::generate_stubs()
void universe2_init() {
EXCEPTION_MARK;
Universe::genesis(CATCH);
}
创建基本类型对应的数组oop TypeArrayKlass
EXCEPTION_MARK;
Universe::genesis(CATCH);
}
创建基本类型对应的数组oop TypeArrayKlass
void referenceProcessor_init() {
ReferenceProcessor::init_statics();
}
初始化统计相关的时钟
ReferenceProcessor::init_statics();
}
初始化统计相关的时钟
void jni_handles_init() {
JNIHandles::initialize();
}
给_global_handles、_weak_global_handles 赋值
JNIHandles::initialize();
}
给_global_handles、_weak_global_handles 赋值
void vmStructs_init() {
debug_only(VMStructs::init());
}
构建一些调试相关的内容,并检查是否设置正确
debug_only(VMStructs::init());
}
构建一些调试相关的内容,并检查是否设置正确
void vtableStubs_init() {
VtableStubs::initialize();
}
初始化继承相关的table
VtableStubs::initialize();
}
初始化继承相关的table
void InlineCacheBuffer_init() {
InlineCacheBuffer::initialize();
}
初始化方法内联缓冲区
InlineCacheBuffer::initialize();
}
初始化方法内联缓冲区
compilerOracle_init()
compilationPolicy_init()
根据命令行参数确定编译策略
根据命令行参数确定编译策略
compileBroker_init()
VMRegImpl::set_regName()
universe_post_init():该方法做了一些预分配的工作
1.预分配一个空的对象数组
2.预分配一些Error Exception
3.设置静态方法用于注册finalizer
1.预分配一个空的对象数组
2.预分配一些Error Exception
3.设置静态方法用于注册finalizer
javaClasses_init()
计算每个类的字段偏移量,并检查它们偏移量计算是否正确,
这个方法必须发生于vtalbe初始化完成之后,也就是类的关系确定之后
计算每个类的字段偏移量,并检查它们偏移量计算是否正确,
这个方法必须发生于vtalbe初始化完成之后,也就是类的关系确定之后
void stubRoutines_init2() { StubRoutines::initialize2(); }
CommandLineFlags::printFlags()
根据名称排序,打印JVM的flag参数设置
根据名称排序,打印JVM的flag参数设置
main_thread->cache_global_variables()
在虚拟机完全创建出来之后应该缓存全局变量
在虚拟机完全创建出来之后应该缓存全局变量
initialize_class(vmSymbols::java_lang_String(), CHECK_0);
initialize_class(vmSymbols::java_lang_System(), CHECK_0);
预加载一些核心类String、System.......
initialize_class(vmSymbols::java_lang_System(), CHECK_0);
预加载一些核心类String、System.......
0 条评论
下一页