首页 > 编程知识 正文

虚拟机信息写在主板上,如何让虚拟机和主机互相ping通

时间:2023-05-06 00:28:27 阅读:11389 作者:3671

写一些友好的代码(下面),对虚拟机友好地编码,我想这是程序员最熟悉的事情。 也是作为程序员最基本的角色,但它是最频繁的,也是最容易自信的。 而且,这种自信有时会成为理所当然的坏习惯。

以前听zzdhb(Oracle高级研究员)说,工作就是让程序员写的代码在虚拟机上跑得多快。 虽然听起来很伟大,但仔细想想,作为程序员的我们。 哪怕能帮上一点忙,不是吗?

在前一篇文章中,我整理了对人友好的代码内容。 简而言之,就是不要写别人不知道的代码,也不要写看着不舒服的代码。

我想分享的是学习虚拟机的运行过程,优化代码,让虚拟机分担压力。 本文还想谈谈自己理解的Java程序员为什么要学习虚拟机。

我听过很多朋友说的话,但我做开发也接触不到虚拟机。 学习这个有什么用呢? 另外,很多朋友在自己被问到或自己在学习虚拟机时会问:“这是什么意思? 你故意为难我吗? 虚拟机能做什么? 你到底学这个有什么用? ”。 如果让我回答这些问题,那就是今天的主题。 为了给机器写温柔的代码。

没办法的虚拟机发现随着时代的发展,我越来越清楚了。 那就是,更多的人不喜欢“浪费时间”。 这里浪费的时间是指懒惰。

如果xfdyd注册APP应用程序帐户时,他的过程太繁琐。 他可能会失去你的用户。 或者另一个游戏如果他玩得太复杂,当然没有人会选择继续玩。 但是,如果这个APP必须注册,而没有其他替代APP,那么他的注册就需要更多的过程,无论多么麻烦,你都必须硬要做,这样做的同时让你觉得“恶心”

就像我们的JAVA虚拟机一样,不管你的代码写得多差,只要语法没有问题,虚拟机就必须完成代码的执行。 但是,你写的代码也可能是虚拟机没有选择的。 他不可能不实行,所以你不是也一边做一边觉得“恶心”吗?

编译程序和优化代码如果不想让虚拟机“恶心”,让我们一起看看虚拟机是如何处理我们写的代码的。 从那里理解对虚拟机友好的代码吧。

编译编译器Java程序有两种含义。 一种是将源代码编译为class格式,另一种是将class格式文件的内容编译为可以直接在计算机上运行的本地计算机代码格式。

在这个过程中一共分为三种编译器

编译器: jdk的javac、eclipse的JDT

即时(JIT )编译器: hotspot的c1 c2 graal

早期(AOT )编译器) jdk的jaOTCGNUcompilerfortheJava(gcj )、Excelsior JET。

前端编译(Javac编译)在此,您可以参考上一篇文章《Java 类的一生》中的Javac培养了解更多信息。 以下叙述前面文章中没有提到的内容。

语法糖可以帮助我们提高开发效率,程序严密,没有实质性的功能提高。

通用地动态化参数

自动拆装箱、强化for循环、可变长度参数

条件编译优化

publicstaticvoidmain (string args [ ] if ) true ) system.out.println ) 1; }else{system.out.println(2; }条件编译优化后

publicstaticvoidmain (string args [ ] ) system.out.println ) 1; } Java语言还有许多其他语法分支程序,包括内部类、枚举类、断言语句、数字文字、枚举和字符串切换支持、try语句中的资源定义和关闭以及Lambda表达式。 (在JDK 8和更高版本的支持下,Lambda不是一个简单的语法糖,但前端编译器执行了许多转换任务。 ) )

后端编译(用JVM编译) IR (程序语言的中间表示(Intermediate Representation ) ) )。

后端编译包括

实时编译技术JIT预编译技术AOT实时编译存在以下问题看后面的内容

为什么HotSpot虚拟机使用解释器和实例编译器共存的体系结构? 为什么HotSpot虚拟机要实现两个或三个不同的即时编译器? 程序什么时候在解释器上运行? 什么时候用编译器运行? 哪个程序代码被编译为本地代码? 如何编译本地代码? 如何从外部观察即时编译器的编译过程和编译结果? 在解释执行过程中,虚拟机发现部分代码经常运行时,称为热点代码。 虚拟机将此代码的一部分预先转换为本地可执行的机器代码,以提高执行效率。

解释器和编译器解释执行

如果需要快速启动和运行程序,解释器将首先发挥作用,节省编译时间并立即运行。

编译执行

程序启动后,随着时间的推移,编译器将起作用,通过将越来越多的代码编译成代价高昂的代码,可以减少解释器的中间损失,获得更高的执行效率

逆优化

当类在程序运行时不断变化时,会出现一些特殊情况(例如

不优化)便会发生逆优化操作继续使用解释执行。

即时编译器分为客户端编译器 C1 和服务端编译器 C2 还有目前在 JDK 10 中处于实验阶段的 Graal编译器(为了替换 C2)

可以通过参数来强制虚拟机仅使用 C1 或 C2 执行

-client”或“-server

解释器与编译器搭配使用的方式在虚拟机中被称为“混合模式”(MixedMode).可以通过 java -version 命令查看

使用参数“-Xint”强制虚拟机运行于“解释模式”(Interpreted Mode),这时候编译器完全不介入工作,全部代码都使用解释方式执行。

使用参数“-Xcomp”强制虚拟机运行于“编译模式”(CompiledMode),这时候将优先采用编译方式执行程序,但是解释器仍然要在编译无法进行的情况下介入执行过程。

使用参数切换执行方式

分层编译

hotspot 中包含多个即时编译器,C1(客户端编译器) C2(服务端编译器) Graal(JDK10引入的实验性质编译器,目标是替换 C2)

JDK 7 以前需要程序特性选择即时编译器

执行时间短、需要快速启动的程序选择 编译速度快 的C1 编译器(参数 -client)执行时间长、对峰值有要求的,选择 执行速度快 的 C2 编译器 (参数 -server)

0 层

解释执行,不开启性能监控

1 层

执行C1 编译的代码,这部分代码是由 C1 快速编译成本地代码,进行一些基本的简单优化(如:方法内联、公共子表达式消除、冗余代码消除,包括冗余访问和冗余存储冗余赋值)

2 层

执行C1 编译的代码,这部分代码是带有方法执行次数和循环回边次数的 profiling (性能监控状态的数据)

3 层

执行 C1 编译的代码,这部分为带所有 profiling 的 C1 代码。

4 层

执行 C2 编译的代码,进行更加复杂的优化内容,同时可能会根据 profiling 做一些激进的优化。

总结

分层编译也可大致分为三层:

0层:解释执行1层:C1 编译执行 对应 1/2/3 层2层0.:C2 编译执行 对应 4 层

其中 1 层和 4 层为最终状态层,当一个方法进入到 C1 的 1 层编译优化后或到达了 C2 的 4 层编译优化后虚拟机在之后的执行中是不会再发出编译请求的了。

编译的对象和条件

编译器编译的对象一般为方法级。

常说“热点代码”会被虚拟机通过即时编译技术进行优化,那什么样的代码才算热点代码?

被多次调用的方法多次执行的循环体(具体有回边次数值)

辨别方法多次调用:

基于采样 虚拟机会周期检测各个线程的栈顶,如果某个方法经常出现在栈顶,则视为热点代码 特点:简单、高效缺点:不准 基于计数器:hotspot 使用这种方式 为每一个方法维护一个调用次数计数器 特点:准确缺点:复杂

识别循环体多次:

根据循环的回边次数进行优化的技术又称为 OSR(On Stack Replacement) —— 栈上替换,因为这部分代码是在执行过程中被优化的,在非方法入口处进行解释执行的代码和编译后的代码进行替换。这个触发条件是有参数 (-XX:CompileThreshold)控制的,计算公式如下

CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)/ 100

参数 -XX:InterpreterProfilePercentage 默认值 33

C1 情况下 OnStackReplacePercentage 默认值 933

C2 情况下 OnStackReplacePercentage 默认值 140

所以在默认情况下, C1 的循环回边次数达到 13500 时会启用 OSR 技术进行即时编译优化代码, C2 则在 10700 时启用。

通常情况下,程序代码不会触发 OSR,在测试中常见

循环回边次数触发的 OSR 技术优化的对象为 代码块。

方法调用次数的优化对象为 整个方法。

提前编译

关于提前编译,我这里只是简单的理解一下。如果对这个感兴趣的话,需要继续找资料深入。我就简单说下我的理解在这里。

Java 程序在早期就拥有这项技术,就是提前把字节码文件编译成机器码。这样就可以加快执行速度。 但是 Java 又想拥有跨平台的小目标,所以也就不好推进。不过另一个ysdxd,Android 做的很好,不过后来是因为提前编译时间太长(安装包安装时间),又不得不使用解释执行和即时编译技术。

编译优化技术

除了上面的两个“热点代码”优化,编译器是如何优化普通的字节码的?首先两个关键的技术 方法内联 逃逸分析

方法内联

将方法的调用,优化成调用者内部代码,省去入栈出栈操作。例如 set get 方法均会被方法内联所优化掉

逃逸分析

分析一个对象的动态作用域,举例来说:

一个对象当做参数传给了另外方法称为 方法逃逸。对一个类变量进行了赋值称为 线程逃逸

通过这两种逃逸方式,可以进行相关优化操作,比如:

一个对象如果没有发生 方法逃逸 ,可以进行栈上分配或者 标量替换(hotspot 使用这种方式进行优化代码)如果一个变量没有发生过 线程逃逸 ,可以进行 同步(锁)消除 优化。

通过逃逸分析,我们可以利用到一点,就是锁消除,即不加锁。而不用是去加了锁,然后等到真正执行时由虚拟机去优化。

循环优化 循环无关代码外提:将循环过程中不变的代码外提至循环外,减少重复的冗余计算循环展开:再循环过程中进行多次迭代,减少循环次数。特殊形式是完全展开;循环判断外提:无关循环的判断移到循环外。循环剥离:循环的前几次或后几次一般可以被优化掉,减少循环次数。 冗余代码消除

公共子表达式消除(对相同的表达式只计算一次,后面的代码复用之前的结果)

int a = b * c + d * e + c * b;// 优化后 b * c 等于 c * b;int a = f + d * e + f;

关于这里,我们是不是可以直接写出 int a = 2f + d * e 的代码呢?让虚拟机也不那么“累”。

冗余访问、存储消除

int a = obj.getValue();// 冗余访问int b = obj.getValue();// 消除后int a = b; int a = obj.getValue();// 冗余存储int b = a;sum = a + b;// 消除后sum = a + a;

还有一些其他的优化手段了解一下。

数组范围检查消除

空值检查消除

自动装箱消除

学习虚拟机的思考

关于虚拟机的学习东西很多,而且很枯燥。能坚持学完除了兴趣,还要有耐心。虽然自己只学习了一些虚拟机的皮毛,但再去写代码的时候,也会有很多帮助,比如你定义的常量值,在 javac 的时候就会被替换成具体的值。也是那为什么你替换了一个常量值文件导致这个值没生效的原因。比如在写代码的时候也能利用一些优化知识来写一些相对精致的代码。比如对自己写下的代码它将来会发生什么比较清楚等等。总之这些价值都不能够直接的体现出来,因为只有你自己才知道。

不要因为一时看不到结果而放弃一些追求,凡事坚持下去终会有结果。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。