JAVA运行

独自空忆成欢 提交于 2019-12-02 02:00:22

JAVA常用的命令行命令的使用,包括基本的概念介绍。

一、JVM、JRE和JDK

JVM(Java Virtual Machine):Java 虚拟机,由软件技术模拟出计算机运行的一个虚拟的计算机。JVM主要识别Java源文件生成的类文件,其主要工作职责是解释字节码并映射到本地的CPU的指令集或者OS的系统调用。不同的操作系统使用不同的 JVM 映射规则,因此实现java平台无关性。它是 Java 程序能在多平台间进行无缝移植的可靠保证,同时也是 Java 程序的安全检验引擎(还进行安全检查)。JVM有自己完善的硬件架构,如处理器、堆、栈、寄存器等,还具有相应的指令系统。

  JVM的内部体系结构分为三个子系统和两大组件,分别是类装载器子系统、执行引擎子系统和GC子系统,组件是内存运行数据区域和本地接口。操作系统装入JVM是通过JDK的Java.exe来完成的(JRE中也有Java.exe),主要分以下几个步骤:
   1.首先便是查找jre路径,获取jre路径后,通过jvm.cfg文件的相关配置等获取JVM类型名,而后获取JVM.dll路径。
   2.找到JVM路径后,通过LoadJavaVM来装入JVM.dll文件,通过调用Windows API函数装入。
   3.装入JVM.dll完成后,初始化JVM,获得本地调用接口,这样就可以在Java中调用JVM的函数了,并获得JNIEnv结构的实例。
   4.运行程序时,通过GetMainClassName函数获取JNIEnv实例,调用其GetStaticMethodID方法可以在类装载后调用类main方法执行。

JRE(Java Runtime Environment):Java运行环境,是运行Java程序所必须的环境的集合,包含JVM标准实现及Java核心类库和支持文件。不包含开发工具(编译器、调试器等)。

  JRE的所有java类库的class文件,都在lib目录下打包成了jar,而虚拟机则是由jre/bin/client下的jvm.dll来转载完成。

JDK(Java Development ToolKit):Java 开发工具包,JDK 是整个 Java 开发的核心。包括Java运行环境(JRE),Java工具(javac、javac、jdb等)和Java基础的类库。

  JDK也包括JRE,其client和server两个文件夹下都包含一个jvm.dll,因此有服务、客户两个虚拟机,服务端虚拟机主要特点是启动慢,但是其编译更完全、CPU、内存和硬盘都比客户端机器强大,因此程序部署后,多以服务端模式启动。而客户端启动快针对桌面应用程序优化,为在客户端环境中减少启动时间而优化。另jre的bin目录最明显的区别就是jdk下才有javac。

二、命令行指令

联编是指一个计算机程序自身彼此关联的过程,在这个联编过程中,需要确定程序中的操作调用(函数调用)与执行该操作(函数)的代码段之间的映射关系;按照联编所进行的阶段不同,可分为静态联编和动态联编;
静态联编是指联编工作是在程序编译连接阶段进行的,这种联编又称为早期联编,因为这种联编是在程序开始运行之前完成的。在编译时就解决了程序中的操作调用与执行该操作代码间的关系,确定这种关系又被称为束定,编译时束定又称为静态束定。
动态联编编译程序在编译阶段并不能确切地知道将要调用的函数,只有在程序执行时才能确定将要调用的函数。为此要确切地知道将要调用的函数,要求联编工作在程序运行时进行,这种在程序运行时进行的联编工作被称为动态联编,或动态束定,又叫晚期联编。C++规定:动态联编是在虚函数的支持下实现的。

  javac [ options ] [ sourcefiles ] [ @files ] 主要用途是编译生成class文件。详细说明

  java [options] mainClass [args...]和java [options] -jar jarfile [args...] 主要用来启动一个java应用。详细说明

  javap 根据class字节码文件,反解析出汇编指令。 详细说明

  jar {ctxui}[vfm0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ... 主要用于打包jar文件。 详细说明

  javadoc [options] [packagenames] [sourcefiles] [@files] 主要用于生成帮助文档。 详细说明

  javah [options] 主要是用于生成头文件 详细说明

示例
  不带包单文件编译、运行:javac xxx.java java xxx
  带包单文件编译、运行:javac -d . xxx.java java package.xxx [命令行参数列表]
  带包且引入其他自定义包类的单文件编译、运行: javac -cp /xx/x -d . xxx.java java -cp /xx/x;. package.xxx
  多文件java类编译: javac -d out xx/xx/.java xx/xx/.java(多文件用空格隔开)或生成编译文件列表用javac -cp /xx/x -d . @xx.list 说明
  jar包说明:jar包根目录下有META-INF文件夹配置主类、ClassPath等、包目录(包目录下为具体包的类)、资源目录(原放在Resources目录下的图片、文件)。
  jar包运行:java -jar xxx.jar (jar包运行项目,取图片资源使用class.getResource方法,且最好用绝对路径)

三、程序运行过程

1.JVM启动流程
  配置JVM装载环境:包括JVM.dll文件的查找和装载。GetJREPath()查找当前JRE环境的所在路径;ReadKnownVms()读取JRE路径\lib\ARCH(CPU构架)\JVM.cfg文件,其中ARCH(CPU构架)通过GetArch方法获取,在window下有三种情况:amd64、ia64和i386;CheckJvmType确定当前JVM类型,先判断是否通过-J、-XXaltjvm=或-J-XXaltjvm=参数指定,如果没有,则读取JVM.cfg文件中配置的第一个类型;GetJVMPath根据上一步确定的JVM类型,找到对应的JVM.dll文件

  LoadLibrary方法装载JVM.dll动态连接库;把JVM.dll文件中定义的函数JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs绑定到InvocationFunctions变量的CreateJavaVM和GetDefaultJavaVMInitArgs函数指针变量上

  虚拟机参数解析:包括参数处理和参数验证。装载完JVM环境之后,需要对启动参数进行解析,其实在装载JVM环境的过程中已经解析了部分参数,该过程通过ParseArguments方法实现,并调用AddOption方法将解析完成的参数保存到JavaVMOption中。AddOption核心就是对-Xss参数进行特殊处理,并设置threadStackSize,因为参数格式比较特殊,其它是key/value键值对,它是-Xss512的格式。后续Arguments类会对JavaVMOption数据进行再次处理,并验证参数的合理性。


  Arguments::parse_each_vm_init_arg方法负责处理经过解析过的JavaVMOption数据,部分实现如下。这里列出了JavaVMOption三个常用的参数:-Xmn:设置新生代的大小NewSize和MaxNewSize;-Xms:设置堆的初始值InitialHeapSize,也是堆的最小值;-Xmx:设置堆的最大值MaxHeapSize;

  Arguments::check_gc_consistency方法负责验证虚拟机启动参数中配置GC的合理性。如果参数为-XX:+UseSerialGC -XX:+UseParallelGC,由于UseSerialGC和UseParallelGC不能兼容,JVM启动时会抛出错误信息;如果参数为-XX:+UseConcMarkSweepGC -XX:+UseParNewGC,其中UseConcMarkSweepGC和UseParNewGC可以兼容,JVM可以正常启动;
  设置线程栈大小:如果启动参数未设置-Xss,即threadStackSize为0,则调用InvocationFunctions的GetDefaultJavaVMInitArgs方法获取JavaVM的初始化参数

  调用JVM.dll函数JNI_GetDefaultJavaVMInitArgs,定义在share\vm\prims\jni.cpp,实现如下。ThreadStackSize定义在globals.hpp中,根据当前系统类型,加载对应的配置文件,所以在不同的系统中,ThreadStackSize的默认值也不同。

  线程栈大小确定后,通过ContinueInNewThread方法创建新线程,并执行JavaMain函数。
2.JavaMain函数执行流程
  新建JVM实例:InitializeJVM方法调用InvocationFunctions的CreateJavaVM方法,即调用JVM.dll函数JNI_CreateJavaVM,新建一个JVM实例。
  加载主类的class:分为jar方式和class方式。jar方式调用GetMainClassName方法找到META-INF/MANIFEST.MF文件指定的Main-Class的主类名。调用LoadClass方法加载主类的class文件。

  class方式,调用NewPlatformString方法创建类名的String对象,调用LoadClass方法加载主类的class文件。

  查找main方法:通过GetStaticMethodID方法查找指定方法名的静态方法,最终调用JVM.dll函数jni_GetStaticMethodID实现。其中get_method_id方法根据类文件对应的instanceKlass对象查找指定方法。


  执行main方法:重新创建参数数组。其中mainID是main方法的入口地址,CallStaticVoidMethod方法最终调用JVM.dll中的jni_CallStaticVoidMethodV函数。最终通过JavaCalls::call执行main方法。


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!