摘要:假设源代码目录为函数函数在,它处理完命令行参数后跳转到函数处理命令行选项函数在,它调用加载这个就是编译的产出在系统下在使用加载动态库并获取函数入口地址在系统下在熟悉的同学,对下面的代码应该会感到很亲切创建对象,并将控制流跳转到呵呵,在
假设 openjdk 源代码目录为 jdk9dev
main函数main 函数在 jdk9dev/jdk/src/java.base/share/native/launcher/main.c,它处理完命令行参数后跳转到 JLI_Launch 函数
int main(int argc, char** argv) { // 处理命令行选项 ... return JLI_Launch(margc, margv, sizeof(const_jargs) / sizeof(char *), const_jargs, appclassc, const_appclasspath, VERSION_STRING, DOT_VERSION, (const_progname != NULL) ? const_progname : *margv, (const_launcher != NULL) ? const_launcher : *margv, HAS_JAVA_ARGS, const_cpwildcard, const_javaw, const_ergo_class); }JLI_Launch
JLI_Launch 函数在 jdk9dev/jdk/src/java.base/share/native/libjli/java.c,
它调用 LoadJavaVM 加载 libjvm.dylib , 这个 libjvm.dylib 就是 hotspot 编译的产出!
int JLI_Launch(...) { ... if (!LoadJavaVM(jvmpath, &ifn)) { return (6); } ... return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret); }LoadJavaVM
在 mac osx 系统下 LoadJavaVM 在 jdk9dev/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c
jboolean LoadJavaVM(const char* jvmpath, InvocationFunctions* ifn) { ... #ifndef STATIC_BUILD libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL); #else libjvm = dlopen(NULL, RTLD_FIRST); #endif ifn->CreateJavaVM = (CreateJavaVM_t) dlsym(libjvm, "JNI_CreateJavaVM"); if (ifn->CreateJavaVM == NULL) { JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } ... }
使用 dlopen 加载动态库并获取 JNI_CreateJavaVM 函数入口地址
JVMInit在 mac osx 系统下 JVMInit 在jdk9dev/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c
熟悉 objc 的同学,对下面的代码应该会感到很亲切:
int JVMInit(InvocationFunctions* ifn, jlong threadStackSize, ...) { ... NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; { JavaLaunchHelper* launcher = [[[JavaLaunchHelper alloc] init] autorelease]; [launcher performSelectorOnMainThread:@selector(launchJava:) withObject:[NSValue valueWithPointer:(void*)&args] waitUntilDone:YES]; rslt = [launcher getReturnValue]; } [pool drain]; return rslt; ... }
创建 JavaLaunchHelper 对象,并将控制流跳转到 launchJava
@implementation JavaLauncherHelper -(int) launchJava:(NSValue*) argsValue { _returValue = JavaMain([argsValue pointerValue]); } @end
呵呵,在 objc 环境短暂停留后控制留又回到 c/c++ 的世界-JavaMain
JavaMainJavaMain 函数在 jdk9dev/jdk/src/java.base/share/native/libjli/java.c,
在 JavaMain 函数中 会初始化 java 虚拟机,查找 main class,获取 main class 的 main 方法,并开始执行 java 字节码
int JNICALL JavaMain(void* _args) { ... // 初始化 jvm if (!InitializeJVM(&vm, &env, &ifn)) { ... } ... // 加载 main class mainClass = LoadMainClass(env, mode, what); ... // 获取 main 方法 mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); ... // 调用 main 方法 (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); LEAVE(); }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/65888.html
摘要:准备工作假设源代码目录为编译时启用了解释器参考编译和调试调用栈先在函数参考虚拟机入口中设断点,然后在的方法中设置断点通过宏获取当前,然后创建第个栈帧,然后进入解释执行字节码 准备工作 假设 openjdk 源代码目录为 jdk9dev 编译 openjdk 时启用了 zero 解释器(参考 OpenJDK9 Hotspot Mac OSX 编译和调试) 调用栈 先在 JavaMai...
摘要:前言语言可以精确控制对象内存分配,出于性能考虑框架系统程序基本都会自己造轮子开发各种内存管理模块也不例外,它通过和方法的访问级别以及重载和方法来管理虚拟机内部对象的内存内存管理相关的基类定义了几个基类来作为大部分对象的基类顾名思义,它们只能 前言 C++ 语言可以精确控制对象内存分配,出于性能考虑 C++ 框架 or 系统程序基本都会自己 造轮子 开发各种内存管理模块. hotspot...
摘要:前言本文从类的方法的内部实现入手,分析多线程相关的数据结构类和原理类方法类的方法用于启动线程,方法内部调用了方法在源代码中搜索,可以看到对应函数在源代码中搜索函数核心代码计算线程堆栈大小创建对象初始化启动线程在创建时传入了一个函数指针, 前言 本文从 Java Thread 类的 start 方法的内部实现入手,分析 Hotspot JVM 多线程相关的数据结构(类)和原理 Threa...
摘要:占用率太高,还出各种奇怪问题,转投调试安装下载源代码漫长等待,中间无数次中断安装安装可选如果要使用解释器,需要安装设置调试级别,设成可以提供更多的调试信息设置路径 Intellij CLion CPU 占用率太高,还出各种奇怪问题,转投 Xcode 调试 hotspot 安装 hg # brew install hg 下载 open jdk 9 源代码 # hg clone http...
摘要:前言网上各路大神总结过各种关于内部实现,看别人的文章总觉得不过瘾,所以有了这篇文章,尝试再扒一次的底裤数据结构在分析源代码之前需要了解相关概念,比如等,参考网络上各种解说或者之前系列文章,这里重点介绍一下,,每个在内部都有一个的对象与之对应 前言 网上各路大神总结过各种关于 hotspot jvm synchronized 内部实现,看别人的文章总觉得不过瘾,所以有了这篇文章,尝试再扒...
阅读 1326·2021-11-11 11:00
阅读 3046·2021-09-24 09:47
阅读 4957·2021-09-22 15:53
阅读 963·2021-09-10 10:50
阅读 3209·2021-09-01 11:40
阅读 1163·2019-08-30 15:55
阅读 476·2019-08-30 12:49
阅读 1051·2019-08-29 17:12