有关java launcher启动JVM时的疑问
yuyinyang
2013-07-11
对于JVM的启动过程我的理解是这样的:
java launcher启动后,会从java.c文件里的 int main(int argc, char ** argv)) 函数进入,然后会create一个新的线程创建JVM并调用方法 int JNICALL JavaMain(void * _args),接下来会在初始化VM的过程中创建一些线程,包括WatcherThread,CompilerThread,GC threads,以及我们运行的java application中create的线程等。在看源码的时候我发现在main()和JavaMain()方法中printf语句并不会在程序运行时打印到标准输出,比如我尝试打印当前线程的kernel tid: /* * Entry point. */ int main(int argc, char ** argv) { ... CreateExecutionEnvironment(&argc, &argv, jrepath, sizeof(jrepath), jvmpath, sizeof(jvmpath), original_argv); printf("Using java runtime at: %s\n", jrepath); fprintf(stdout, "Before calling JavaMain, tid is %d\n", syscall(__NR_gettid)); ifn.CreateJavaVM = 0; ... 但是在编译hotspot的时候会打印出来: 引用 ... Linking launcher... gcc -m64 -Xlinker -O1 -Xlinker -z -Xlinker noexecstack -m64 -Xlinker -export-dynamic -L `pwd` -o gamma launcher/java_md.o launcher/java.o launcher/jli_util.o launcher/wildcard.o -ljvm -lm -ldl -lpthre ad make[6]: Leaving directory `/home/yuyinyang/openjdk_b147_27_yy/openjdk/build/linux-amd64/hotspot/outputdir/linux_amd64_compiler2/product' All done. make[5]: Leaving directory `/home/yuyinyang/openjdk_b147_27_yy/openjdk/build/linux-amd64/hotspot/outputdir/linux_amd64_compiler2/product' cd linux_amd64_compiler2/product && ./test_gamma java full version "1.6.0_18-b18" Using java runtime at: /usr/lib/jvm/java-6-openjdk/jre Before calling JavaMain, tid is 27228 In JavaMain, initializing VM, tid is 27229 所以我想知道这是什么原因呢,难道是运行java程序的时候不是从这entry的吗?感觉不太可能...或者是输出被重定向了?但是我没找到重定向的代码。求解惑 |
|
RednaxelaFX
2013-07-11
您的疑问是不是说自己修改了java launcher的代码,但却没看到效果?
那请问您改的具体是什么路径上的java.c,编译是用什么命令在哪个目录执行的? 看您描述的执行结果,看起来您是改了hotspot/share/tools/launcher下的java.c,编译是单独编译了HotSpot VM(只改了那个java.c的话,或者编译整个OpenJDK也一样就是了)。 构建hotspot目录的内容的过程中会生成一个叫做gamma launcher的东西,专门用来针对HotSpot VM做简易测试用的。其主体代码就在hotspot/share/tools/launcher里。您会在代码里看到ifdef GAMMA,那种就是专门给gamma launcher用的代码。 25 /* 26 * Gamma (Hotspot internal engineering test) launcher based on 6.0u22 JDK, 27 * search "GAMMA" for gamma specific changes. 28 * 29 * GAMMA: gamma launcher is much simpler than regular java launcher in that 30 * JVM is either statically linked in or it is installed in the 31 * same directory where the launcher exists, so we don't have to 32 * worry about choosing the right JVM based on command line flag, jar 33 * file and/or ergonomics. Intead of removing unused logic from source 34 * they are commented out with #ifndef GAMMA, hopefully it'll be easier 35 * to maintain this file in sync with regular JDK launcher. 36 */ 而实际上“java”这个命令对应的launcher的代码不在hotspot目录里,而在jdk/src/share/bin目录里。所以要修改JDK里的java命令的实现,就得修改jdk这边的java.c(或者jdk/src/<platform>/bin里的平台相关代码),并且构建整个JDK得到j2se-image(或者对应的debug版)才行。或者至少构建jdk目录,而不是hotspot目录,来获得那个java launcher。 |
|
yuyinyang
2013-07-12
R大,我按照你说的修改了jdk/src/share/bin目录下的java.c文件,运行的时候看到了效果,多谢。
我还有个问题,应用程序创建的线程(main函数的主线程除外)在hotspot里是如何创建的?我知道貌似在linux平台下,所有的新线程的创建都是在src/os/linux/vm/os_linux.cpp文件中进行pthread_create的,每个新创建的线程都是从一个叫java_start的方法进入的,我尝试对这些进行跟踪并打印线程id,找到了gc thread,compiler thread等线程的构造函数等,但是找不到应用程序里用户创建的线程从哪构造的,请求R大指点。 |
|
RednaxelaFX
2013-07-12
yuyinyang 写道 R大,我按照你说的修改了jdk/src/share/bin目录下的java.c文件,运行的时候看到了效果,多谢。
OK,那就好~ yuyinyang 写道 我还有个问题,应用程序创建的线程(main函数的主线程除外)在hotspot里是如何创建的?我知道貌似在linux平台下,所有的新线程的创建都是在src/os/linux/vm/os_linux.cpp文件中进行pthread_create的,每个新创建的线程都是从一个叫java_start的方法进入的,我尝试对这些进行跟踪并打印线程id,找到了gc thread,compiler thread等线程的构造函数等,但是找不到应用程序里用户创建的线程从哪构造的,请求R大指点。
Java层的入口是java.lang.Thread.start()。 它的native实现在:jdk/src/share/native/java/lang/Thread.c, {"start0", "()V", (void *)&JVM_StartThread} 对应的HotSpot VM部分的实现在:hotspot/src/share/vm/prims/jvm.cpp, JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) |
|
yuyinyang
2013-07-15
如果不是您指出来真心找不到那里去,这个entry的代码是用宏定义的,都没法跟踪调用...
我研究一下你说的这部分代码JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)),我发现并非只有java层的mutator线程会从这里调用,貌似还有其他的线程是从这里进入的,您能告诉我是些什么线程吗? |
|
RednaxelaFX
2013-07-15
yuyinyang 写道 如果不是您指出来真心找不到那里去,这个entry的代码是用宏定义的,都没法跟踪调用...
我研究一下你说的这部分代码JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)),我发现并非只有java层的mutator线程会从这里调用,貌似还有其他的线程是从这里进入的,您能告诉我是些什么线程吗? 这里传入的jthread参数只能是java.lang.Thread及其子类的实例,也就是说只能是Java线程。虽然不是所有Java线程都是用户线程(例如说FinalizerThread、Service Thread之类,这些是提供JVM底层服务的线程而不是用户线程),但从JVM的角度看它们有共同特点就是可以执行Java代码。 另外JVM_StartThread当然是可以跟踪调用的。JVM_ENTRY只是个很简单的宏,并不改变声明的函数的名字,在函数体里设断点没问题的。最好用fastdebug build来调试而不要用product build |
|
yuyinyang
2013-07-16
R大,我看到这篇帖子:http://hllvm.group.iteye.com/group/topic/28934
您之后有用到intel的icc编过openjdk吗?或者您知道用icc编具体需要修改些哪些文件、如何修改吗? |
|
RednaxelaFX
2013-07-16
yuyinyang 写道 R大,我看到这篇帖子:http://hllvm.group.iteye.com/group/topic/28934
您之后有用到intel的icc编过openjdk吗?或者您知道用icc编具体需要修改些哪些文件、如何修改吗? 我自己没用ICC编译过OpenJDK,所以抱歉我没啥经验可分享了。可以试试问那帖的楼主看他积累了些什么经验~ |
|
yuyinyang
2013-07-16
RednaxelaFX 写道 yuyinyang 写道 R大,我看到这篇帖子:http://hllvm.group.iteye.com/group/topic/28934
您之后有用到intel的icc编过openjdk吗?或者您知道用icc编具体需要修改些哪些文件、如何修改吗? 我自己没用ICC编译过OpenJDK,所以抱歉我没啥经验可分享了。可以试试问那帖的楼主看他积累了些什么经验~ 好的,谢谢R大~ |