无话不谈|离 Linux 内核有多远?,Java

Java离内核有多远?测试环境版本信息:
每次提起Java , 我都会想到一段有趣的经历 。 刚毕业到部门报到第一个星期 , 部门领导(在华为算是Manager)安排我们熟悉Android 。 我花了几天写了个Android游戏 , 有些类似连连看那种 。 开周会的时候 , 领导看到我的演示后 , 一脸不悦 , 质疑我的直接领导(在华为叫PL , ProjectLeader)没有给我们讲明白部门的方向 。
emm , 我当时确实没明白所谓的熟悉Android是该干啥 , 后来PL说 , 是要熟悉xxx模块 , APP只是其中一部分 。 话说如果当时得到的是肯定 , 也许我现在就是一枚Java工程师了(哈哈手动狗头) 。
从launcher说起世界上最远的距离 , 是咱俩坐隔壁 , 我在看底层协议 , 而你在研究spring……如果想拉近咱俩的距离 , 先下载openjdk源码 , 然后下载glibc , 再下载内核源码 。
Java程序到JVM , 这个大家肯定比我熟悉 , 就不班门弄斧了 。
我们就从JVM的入口为例 , 分析JVM到内核的流程 , 入口就是main函数了(java.base/share/native/launcher/main.c):
JNIEXPORTintmain(intargc,char**argv){//中间省略一万行参数处理代码returnJLI_Launch(margc,margv,jargc,(constchar**)jargv,0,NULL,VERSION_STRING,DOT_VERSION,(const_progname!=NULL)?const_progname:*margv,(const_launcher!=NULL)?const_launcher:*margv,jargc>0,const_cpwildcard,const_javaw,0);}JLI_Launch做了三件我们关心的事 。
首先 , 调用CreateExecutionEnvironment查找设置环境变量 , 比如JVM的路径(下面的变量jvmpath) , 以我的平台为例 , 就是/usr/lib/jvm/java-14-openjdk-amd64/lib/server/libjvm.so , window平台可能就是libjvm.dll 。
其次 , 调用LoadJavaVM加载JVM , 就是libjvm.so文件 , 然后找到创建JVM的函数赋值给InvocationFunctions的对应字段:
jbooleanLoadJavaVM(constchar*jvmpath,InvocationFunctions*ifn){void*libjvm;//省略出错处理libjvm=dlopen(jvmpath,RTLD_NOW+RTLD_GLOBAL);ifn->CreateJavaVM=(CreateJavaVM_t)dlsym(libjvm,"JNI_CreateJavaVM");ifn->GetDefaultJavaVMInitArgs=(GetDefaultJavaVMInitArgs_t)dlsym(libjvm,"JNI_GetDefaultJavaVMInitArgs");ifn->GetCreatedJavaVMs=(GetCreatedJavaVMs_t)dlsym(libjvm,"JNI_GetCreatedJavaVMs");returnJNI_TRUE;}dlopen和dlsym涉及动态链接 , 简单理解就是libjvm.so包含JNI_CreateJavaVM、JNI_GetDefaultJavaVMInitArgs和JNI_GetCreatedJavaVMs的定义 , 动态链接完成后 , ifn->CreateJavaVM、ifn->GetDefaultJavaVMInitArgs和ifn->GetCreatedJavaVMs就是这些函数的地址 。
不妨确认下libjvm.so有这三个函数 。
objdump-D/usr/lib/jvm/java-14-openjdk-amd64/lib/server/libjvm.so|grep-E"CreateJavaVM|GetDefaultJavaVMInitArgs|GetCreatedJavaVMs"|grep":$"00000000008fa9d0:00000000008faa20:00000000009098e0:openjdk源码里有这些实现的(hotspot/share/prims/下) , 有兴趣的同学可以继续钻研 。
最后 , 调用JVMInit初始化JVM , loadJava程序 。
JVMInit调用ContinueInNewThread , 后者调用CallJavaMainInNewThread 。 插一句 , 我是真的不喜欢按照函数调用的方式讲述问题 , a调用b , b又调用c , 简直是在浪费篇幅 , 但是有些地方跨度太大又怕引起误会(尤其对初学者而言) 。 相信我 , 注水 , 是真没有 , 我不需要经验+3哈哈 。


推荐阅读