
根据不同的配置生效的不同,再重新配置一下试试。
JDK安装完成后,将可在jdk安装路径下看到如下几个主要文件路径:
1)bin:该路径下存放了JDK的各种工具命令,常用的javac、java等命令。
2)demo:该路径下存放了JDK提供的演示代码。
3)jre:该路径下存放了运行java程序所必需的JRE环境。
4)lib:该路径下存放的是JDK工具命令的实际执行程序。
编译和运行java程序必须经过两个步骤:
1)将源文件编译成字节码(用java命令)
2)解释执行平台无关的字节码程序(用javac命令)
然而,计算机如何查找这两个命令呢?这就要在JDK安装完成后,设置PATH环境变量。
1)Windows *** 作系统中,根据Path环境变量来查找命令。Path环境变量的值是一系列路径,Windows *** 作系统将会在这一系列的路径中查找命令,如果找到这个命令,则该命令是可执行的;否则将出现”XXX不是内部或外部命令,也不是可运行的程序或批处理文件“的提示。
2)Linux *** 作系统则根据PATH环境变量来查找命令,PATH环境变量的值也是一系列路径。因为Windows *** 作系统不区分大小写,设置Path和PATH并没有区别;而Linux系统是区分大小写的,设置Path和PATH是有区别的。
先装个JDK记住你装的路径 默认的是"C:\Program Files\Java\jdk160_17\bin"然后运行中输入cmd回车,将目录定位到你的java文件的目录上,('cd'是进入一个目录,'cd'是向上一层目录)然后输入 path=%path%;D:\Program Files\Java\jdk160_17\bin (如果你是默认安装的话不是就用你的目录)然后在输入javac 你的类名java编译通过后就有你要的class文件
javac参数 编译警告关闭_JVM之JIT即时编译 原创
2020-12-26 08:21:34

水天姬 
码龄4年
关注

当今Java语言被广为接受的优点之一就有即时编译,即时编译的存在使得Java应用可以运行时间的增长而获得更高的性能。
如果有对jvm做过研究的朋友,一定听说过这样一段话:由于即时编译技术的进步,尤其是逃逸分析技术的日渐强大,栈上分配、标量替换优化手段已经导致一些微妙的变化悄然发生,Java对象实例都分配在堆上也变得不那么绝对了。虚拟机发展到今天,即时编译也是我们对jvm讨论的话题之一,今天我也来对即时编译进行一个详述。
JIT(just-in-time)
Coding的哔哔叨叨
JIT即just-in-time的缩写,即时编译技术,可以加快java的执行速度。我们都知道,从源代码,经javac编译生成class文件字节码,在经过类加载器,加载到内存,jvm通过解释字节码翻译成对应的机器指令,逐条读入,逐条翻译解释,这就是 jvm解释执行的过程。
很显然,解释执行,其执行速度必然会比可执行的二进制字节码程序慢很多,为了提高执行速度,引入了即时编译技术。
Java程序最初是通过解释器(interpreter)进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁,就会把这些代码认为是“热点代码”。为了提高热点代码的执行效率,在运行时,虚拟机会把这些代码编译成与本地机器相关的机器码,并进行各种层次的优化,完成这个任务的编译器称之为“即时编译器(just-in-time compiler)”。
注意:即时编译器并不是java虚拟机的必须部分,java虚拟机规范并没有规定必须要有即时编译器的存在,并且,更没有要求或指导如何实现即时编译器;但是即时编译器的好坏、代码优化程度高低却是衡量一款商用虚拟机的重要指标之一,它也是虚拟机最核心且最能体现虚拟机技术水平的的部分。
由于上述原因,所以即时编译器完全是某虚拟机具体实现的相关内容,所以,如无特殊说明,本文所提到的即时编译器都是Hotspot虚拟机内的即时编译器;所提到的虚拟机也是专门特指Hotspot虚拟机。
JVM运行原理
Coding的哔哔叨叨
这儿我们贴出一张图,大家结合着图进行理解即可。


为什么Hotspot要使用解释器与编译器并存的架构?
Coding的哔哔叨叨
首先要说明,并不是所有的虚拟机实现都采用解释器与编译器并行的方案,但许多的主流虚拟机,如Hotspot,都同时包含解释器和编译器。解释器与编译器各有优势: 当程序需要快速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行;当程序运行环境内存资源限制较大(如嵌入式系统),可以使用解释器节约内存。反之可以使用编译器提高执行效率,此外,编译后如果出现“罕见陷阱”,可以逆优化退回到解释执行。

编译的时间开销
Coding的哔哔叨叨
我们先抽象看下解释器和编译器的执行过程。
解释器:输入代码->[解释器解释执行]->执行结果
编译器:输入代码->[编译器编译]->编译后的代码->执行结果。
从上面的抽象执行过程来看,JIT编译执行,要比解释执行慢,多了一个执行编译后代码的过程,所以针对“只执行一次的代码”,解释执行总要比编译执行快。而我们通常所说的,JIT编译执行,比解释执行快,并不是说“编译”这个动作比“解释”这个动作快,而是在非“只执行一次的代码”环境下,JIT编译执行要比解释执行快,要注意这个前提环境,而我们所指的不止执行一次的代码,有以下两个场景:
方法被多次调用,相反类似类构造器(class initializer,())只被调用一次。
存在循环。
只有频繁执行的代码,才会保证JIT编译执行的正向收益。
编译的空间开销
Coding的哔哔叨叨
对java语言来说,编译后的代码相对于class字节码,膨胀达10倍是很正常的,同上面所说的时间开销一样,只有针对频繁执行的代码,才能保证有正向收益,才值得去编译,如果把所有的代码都进行编译,会很明显的增加代码所占空间。
JIT编译,会将编译后的汇编指令保存在代码缓存中,代码缓存是固定大小的,当jvm代码缓存一旦被填满,jvm就不能编译更多的代码。
所以,这也解释了,为什么虚拟机不完全采用JIT编译执行,而是选择解释器与编译器混合共存的执行引擎。
现在并没有一个好的机制可以确定一个特定的应用到底需要多大的代码缓存。因此,当需要提高代码缓存时,这将是一种凑巧的 *** 作,一个通常的做法是将代码缓存变成默认大小的两倍或四倍。
可以通过 –XX:ReservedCodeCacheSize=Nflag(N 就是之前提到的默认大小)来最大化代码缓存大小。代码缓存的管理类似于 JVM 中的内存管理:有一个初始大小(用-XX:InitialCodeCacheSize=N 来声明)。代码缓存的大小从初始大小开始,随着缓存被填满而逐渐扩大。代码缓存的初始大小是基于芯片架构(例如 Intel 系列机器,client 编译器模式下代码缓存大小起始于 160KB,server 编译器模式下代码缓存大小则起始于 2496KB)以及使用的编译器的。重定义代码缓存的大小并不会真正影响性能,所以设置 ReservedCodeCacheSize 的大小一般是必要的。
再者,如果 JVM 是 32 位的,那么运行过程大小不能超过 4GB。这包括了 Java 堆,JVM 自身所有的代码空间(包括其本身的库和线程栈),应用程序分配的任何的本地内存,当然还有代码缓存。
所以说代码缓存并不是无限的,很多时候需要为大型应用程序来调优(或者甚至是使用分层编译的中型应用程序)。比如 64 位机器,为代码缓存设置一个很大的值并不会对应用程序本身造成影响,应用程序并不会内存溢出,这些额外的内存预定一般都是被 *** 作系统所接受的。
Hotspot的两个不同编译器
Coding的哔哔叨叨
Hotspot内置了两个解释编译器: client compiler(c1)和server compiler(c2),分别用在客户端和服务端。HotSpot虚拟机会根据自身版本与宿主机器的硬件性能自动选择运行模式,用户也可以使用“-client”或“-server”参数去强制指定虚拟机运行在Client模式或Server模式。c1编译器有更快的编译速度,c2编译器有更高的编译质量。
哪些代码会被即时编译?
Coding的哔哔叨叨
哪些代码会被称为热点代码,其实我们在上面也提过过,以下两种场景:
被多次调用的方法。
被多次执行的循环体。
注意:上面两种情况,编译器都是以整个方法作为编译对象,编译方法发生在方法执行过程中,我们称之为:栈上替换(OSR,On Stack Replacement),方法栈针还在栈上,方法就被替换了。
如何编译为本地代码?
Coding的哔哔叨叨
Server Compiler和Client Compiler两个编译器的编译过程是不一样的。 对Client Compiler来说,它是一个简单快速的编译器,主要关注点在于局部优化,而放弃许多耗时较长的全局优化手段。 而Server Compiler则是专门面向服务器端的,并为服务端的性能配置特别调整过的编译器,是一个充分优化过的高级编译器。
HotSpot的热点探测技术
Coding的哔哔叨叨
目前主流的热点探测技术有两种:
基于采样的热点探测
从字面也能基本理解,这种方法基本是周期性的检查各个线程的栈顶,如果发现某个方法经常性的出现在栈顶,那么这个方法就是“热点代码”。这种方式简单有效,但是也存在很明显的问题,很难精准的确认一个方法是热点方法,容易因为线程阻塞或者其他的一些外界因素的影响而扰乱热点探测。
基于计数器的热点探测
采用这种方式的虚拟机会为每个方法(甚至是代码)建立计数器,统计方法的执行次数,如果执行次数超过一定的阈值,就认为是“热点方法”。这种方式实现起来就复杂了,需要为每个方法建立并维护计数器,而且不能直接获取方法的调用关系,但是这种方式的统计结果就相对精确严谨。 Hotspot虚拟机采用的是计数器热点探测方式。 ,为每个方法都维护了两个计数器:方法调用计数器和回边计数器。在确定虚拟机参数的前提下,这两个计数器都有一个确定的阈值,当计数器超过阈值溢出了,就会触发JIT编译。
方法调用计数器
顾名思义,这个计数器用于统计方法被调用的次数。当一个方法被调用时,会先检查该方法是否存在被JIT编译过的版本,如果存在,则优先使用编译后的本地代码来执行。如果不存在已被编译过的版本,则将此方法的调用计数器值加1,然后判断方法调用计数器与回边计数器值之和是否超过方法调用计数器的阈值。如果超过阈值,那么将会向即时编译器提交一个该方法的代码编译请求。如果不做任何设置,执行引擎并不会同步等待编译请求完成,而是继续进行解释器按照解释方式执行字节码,直到提交的请求被编译器编译完成。当编译工作完成之后,这个方法的调用入口地址就会系统自动改写成新的,下一次调用该方法时就会使用已编译的版本。

回边计数器
它的作用就是统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为“回边”。
JIT的知识点,大部分应该都提到了,还有啥没提到的,留言,补充。
文章部分来源于网络其他优秀工程师的分享。
最后还想给大家补充个知识点,关于java的javac编译和即时编译。在刚开始接触到java的时候,每次谈到编译,总是搞不清到底说的是那种编译,在这也简单聊一下,给大家做个简单的区分。
javac编译与JIT编译
Coding的哔哔叨叨
我们通常所说的编译,有两种情形,一种是从源代码(java)编译为字节码(class);一种是虚拟机执行字节码的过程,从字节码编译为本地机器语言。所以在提到编译的时候,一定要区分清是哪种(刚开始结束java的时候被这个搞得晕乎的很久)。我们一般把javac的编译过程称之为:前端编译;把JIT编译称之为后端编译。如果可能,下篇文章,我把java的前端编译过程进行一下说明。
不积跬步,无以至千里。
文章有帮助的话,点个转发、在看呗。
谢谢支持哟 (^__^)
END


相关资源:java编译器源码解析-warnings-ng-plugin:Jenkins警告插件-下一代
java中负责对字节代码解释执行的是虚拟机,虚拟机将得到的字节代码进行编码运行。
java程序,是先把java源程序通过javac命令编译成字节码文件,然后再用java命令解释执行。把字节码文件复制到其它计算机上,只要有java虚拟机就可以用java命令来执行。
以上就是关于如何解决安装java时出现程序包有问题不能运行的问题全部的内容,包括:如何解决安装java时出现程序包有问题不能运行的问题、怎么将java程序转换为字节码文件、编译告警被关闭的参数等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)