从源码追踪java程序的执行过程

1。首先在路径下写一个Hello.java的程序:--------------D:\项目管理\个人项目\手写java\hello_world

public class Hello 
{
	public static void main(String[] args) 
	{
		System.out.println("Hfddlo World!");
	}
}

进入到Java的安装目录:

输入:javac D:\项目管理\个人项目\手写java\hello_world\Hello.java -d D:\项目管理\个人项目\手写java\hello_world

 javac 的代码:


jdk的bin目录下执行如下命令:

java -classpath D:\项目管理\个人项目\手写java\hello_world Hello

给java的Hello类加上包名:

将编译好的Hello.class放入到/com/test/ 目录下:

 运行:java -classpath D:\项目管理\个人项目\手写java\hello_world com.test.Hello

 java后面的参数

1.    -cp是-classpath的缩写

2. --help        将此帮助消息输出到输出流
    -X            将额外选项的帮助输出到错误流

 -d <module name>
    --describe-module <模块名称>
                  描述模块并退出
    --dry-run     创建 VM 并加载主类, 但不执行 main 方法。
                  此 --dry-run 选项对于验证诸如
                  模块系统配置这样的命令行选项可能非常有用。

3. --boot-class-path <path>, -bootclasspath <path>
        覆盖引导类文件的位置
  --class-path <path>, -classpath <path>, -cp <path>
        指定查找用户类文件和注释处理程序的位置
  -d <directory>               指定放置生成的类文件的位置

-g                           生成所有调试信息

 --release <release>          针对特定 VM 版本进行编译。支持的目标: 6, 7, 8, 9
  -s <directory>               指定放置生成的源文件的位置
  -source <release>            提供与指定发行版的源兼容性

 -Werror                      出现警告时终止编译



源码追踪:

命令行运行java -version

程序会走到:D:\项目管理\个人项目\jdk源码解读\openjdk7\openjdk\jdk\src\share\bin\main.c   的第96行:

/*
 * 程序的入口
 */
#ifdef JAVAW

char **__initenv;

int WINAPI
WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow)
{
    int margc;
    char** margv;
    const jboolean const_javaw = JNI_TRUE;

    __initenv = _environ;
    margc = __argc;
    margv = __argv;


#else /* JAVAW */
int
main(int argc, char ** argv)
{
    int margc;
    char** margv;
    const jboolean const_javaw = JNI_FALSE;

    margc = argc;
    margv = argv;
#endif /* JAVAW */

    return JLI_Launch(margc, margv,
                   sizeof(const_jargs) / sizeof(char *), const_jargs,
                   sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
                   FULL_VERSION,
                   DOT_VERSION,
                   (const_progname != NULL) ? const_progname : *margv,
                   (const_launcher != NULL) ? const_launcher : *margv,
                   (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,
                   const_cpwildcard, const_javaw, const_ergo_class);
}

JLI_Launch在java.c中,关键代码:

int
JLI_Launch(int argc, char ** argv,              /* main argc, argc */
        int jargc, const char** jargv,          /* java args */
        int appclassc, const char** appclassv,  /* app classpath */
        const char* fullversion,                /* full version defined */
        const char* dotversion,                 /* dot version defined */
        const char* pname,                      /* program name */
        const char* lname,                      /* launcher name */
        jboolean javaargs,                      /* JAVA_ARGS */
        jboolean cpwildcard,                    /* classpath wildcard*/
        jboolean javaw,                         /* windows-only javaw */
        jint ergo                               /* ergonomics class policy */
)
{...............................   
/* 解析命令行的参数; 如果命令行参数错误* 就终止程序
     */
    if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath))
    {
        return(ret);
    }

............
}

进入这个函数看看::

/**
 * bool为C中变量类型,jboolean 为JNI中变量类型,boolean为Java中变量类型;
jboolean在C语言的定义为:
typedef unsigned char jboolean;
unsigned char是无符号字节型,char类型变量的大小通常为1个字节(1字节=8个位),且属于整型;说明jboolean在C语言中取值为0或1,且有如下宏定义:
#define JNI_FALSE 0
#define JNI_TRUE 1
 */
static jboolean
ParseArguments(int *pargc, char ***pargv,
               int *pmode, char **pwhat,
               int *pret, const char *jrepath)
{.................

  while ((arg = *argv) != 0 && *arg == '-') {
        argv++; --argc;
        if (JLI_StrCmp(arg, "-classpath") == 0 || JLI_StrCmp(arg, "-cp") == 0) {
            ARG_CHECK (argc, ARG_ERROR1, arg);
            SetClassPath(*argv);
            mode = LM_CLASS;
            argv++; --argc;
        } else if (JLI_StrCmp(arg, "-jar") == 0) {
            ARG_CHECK (argc, ARG_ERROR2, arg);
            mode = LM_JAR;
        } else if (JLI_StrCmp(arg, "-help") == 0 ||
                   JLI_StrCmp(arg, "-h") == 0 ||
                   JLI_StrCmp(arg, "-?") == 0) {
            printUsage = JNI_TRUE;
            return JNI_TRUE;
        } else if (JLI_StrCmp(arg, "-version") == 0) {
            printVersion = JNI_TRUE;
            return JNI_TRUE;
        } else if (JLI_StrCmp(arg, "-showversion") == 0) {
            showVersion = JNI_TRUE;
        } else if (JLI_StrCmp(arg, "-X") == 0) {
            printXUsage = JNI_TRUE;
            return JNI_TRUE;
...................
  if (--argc >= 0) {
        *pwhat = *argv++;
    }

    if (*pwhat == NULL) {
        *pret = 1;
    } else if (mode == LM_UNKNOWN) {
        /* default to LM_CLASS if -jar and -cp option are
         * not specified */
        mode = LM_CLASS;
    }

    if (argc >= 0) {
        *pargc = argc;
        *pargv = argv;
    }

    *pmode = mode;

    return JNI_TRUE;
}
.....
}

解析到了version,返回JNI_TRUE,

2.仍然是JLI_Launch()函数:    -----------------------    从命令行拿到类的路径

 if (IsJavaArgs()) {
        /* Preprocess wrapper arguments */
        TranslateApplicationArgs(jargc, jargv, &argc, &argv);
        if (!AddApplicationOptions(appclassc, appclassv)) {
            return(1);
        }
    } else {
        /* Set default CLASSPATH */
        cpath = getenv("CLASSPATH");
        if (cpath == NULL) {
            cpath = ".";
        }
        SetClassPath(cpath);
    }

JLI_LAUCH()下的 SetJavaLauncherPlatformProps()


    /* 获取当前进程id,放入参数 -D sun。java。laucher。pid,这样jvm就知道他的创建者的进程ID */
    SetJavaLauncherPlatformProps();

 在来看看这个方法:

 进去看看:创建虚拟机,调用客户自己写的java程序,主类的Main()函数进入。

static int
ContinueInNewThread(InvocationFunctions* ifn, int argc, char **argv,
                    int mode, char *what, int ret)
{

    /*未指定堆大小 ----通过init args(初始的参数)结构返回其默认堆栈大小 
     * If user doesn't specify stack size, check if VM has a preference.
     * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will
     * return its default stack size through the init args structure.
     */
    if (threadStackSize == 0) {
      struct JDK1_1InitArgs args1_1;
      memset((void*)&args1_1, 0, sizeof(args1_1));
      args1_1.version = JNI_VERSION_1_1;
      ifn->GetDefaultJavaVMInitArgs(&args1_1);  /* ignore return value */
      if (args1_1.javaStackSize > 0) {
         threadStackSize = args1_1.javaStackSize;
      }
    }
   /**创建一个线程去创建
    * jvm 虚拟机和调用java主类中的main()主函数方法
    * */
    { /* Create a new thread to create JVM and invoke main method */
      JavaMainArgs args;
      int rslt;

      args.argc = argc;
      args.argv = argv;
      args.mode = mode;
      args.what = what;
      args.ifn = *ifn;

      rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args);
      /* If the caller has deemed there is an error we
       * simply return that, otherwise we return the value of
       * the callee
       */
      return (ret != 0) ? ret : rslt;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41063141/article/details/89435870