Java虚拟机——后端编译与优化

news2024/11/24 15:32:27
  • 编译器无论在何时、何种状态下将Class文件转换成与本地基础设施相关的二进制机器码,它都可以视为整个编译过程的后端。
  • 即时编译一直是绝对主流的编译形式,不过提前编译也逐渐被主流JDK支持。

1 即时编译器

  • 目前两款主流的Java虚拟机(HotSpot、OpenJ9里面),Java程序都是通过解释器进行解释执行的。当虚拟机认为某个方法或代码块的运行特别频繁,就会把这些代码编译成本地机器码,运行时完成这个任务的编译器叫作即时编译器

1.1 解释器与编译器

  • 目前主流的Java虚拟机都采用了解释器与编译器并存的运行架构。
  • 当程序需要快速启动和执行的时候,解释器可以首先发挥作用,省去编译时间,立刻运行。当程序启动后,随着时间地推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码,这样可以减少解释器中间的损耗。
  • HotSpot虚拟机内置了两个(或三个)即时编译器,其中两个编译器存在以及。分别是客户端编译器(C1编译器)服务端编译器(C2编译器),第三个是JDk10时出现,为了代替C2的Graal编译器
  • 为了在程序启动相应速度与运行效率之间达到最佳平衡状态,HotSpot虚拟机在编译子系统中加入了分层编译的功能。
    在这里插入图片描述

分层编译的好处是什么?

  1. 实施分层编译后,解释器、客户端编译器、服务端编译器就会同时工作,热点代码可能被多次编译。
  2. 用客户端编译器可以获得更高的编译速度,用服务端编译器来获取更好的编译质量,在解释执行的时候也无须承担收集性能监控信息的任务。
    在这里插入图片描述

2 编译对象与触发条件

  • 本章概述中提到了在运行过程中会被即时编译器编译的目标是"热点代码",这里所指的热点代码主要有两类。
  1. 被多次调用的方法
  2. 被多次调用的循环体
  • 对于这两种情况,编译的目标对象都会是整个方法体,而不是单独的循环体。
    在这里插入图片描述

3 编译过程

  • 无论是方法调用产生的标准编译请求,还是栈上替换编译请求。虚拟机在编译器还未完成编译之前,都将按照解释方法继续执行代码。

  • 而编译动作会进行在后台的编译线程中。

  • 在后台编译执行的过程中,服务端编译器和客户端编译器的编译过程是有差别的。

  • 客户端编译器

  • 它是一个相对简单快速的三段式编译器,主要的关注点在于局部性的优化,而放弃了许多耗时较长的全局优化手段。
    在这里插入图片描述

  • 服务端编译器

  • 它是一个专门面向服务端典型用场景的、为服务端的性能配置针对性调整过 的 编译器。
    在这里插入图片描述

2 提前编译器

  • 提前编译的发展,直到在Android的世界里,使用了提前编译的ART,ART一诞生就把使用即时编译器的Dalvik虚拟机按在地上使劲蹂躏。

提前编译的优劣得失?

  • 优点
  1. 提前编译没有执行时间和资源限制的压力,能够毫无顾虑地使用重负载优化手段。
  • 缺点
  1. 最传统的提前编译应用形式,就是在程序运行之前把程序代码编译成机器码的静态翻译工作。但是它会占用程序运行时间和运算资源。
  2. 提前编译的第二条途径,就是将编译工作提前做好后保存下来,下次运行到这块代码的时候,就直接加载进来使用。但是这种即时编译缓存输出的代码质量反而要低于即时编译器。

3 编译器优化技术

  • 编译器的目标就是由程序代码翻译成本地机器码的工作
  • 但是它的难点不在于能不能成功翻译出机器码,而是输出代码优化质量的高低。
  • 即时编译器优化技术的数量有很多,接下来会介绍几种常用的优化技术。并且通过Java代码变化来展示,不过即时编译器对这些代码优化变化是建立在 代码的中间表示或者是机器码之上的。

基础案例

package Compilation;

public class BasicDemo {
    B b = new B();
    int y , z , sum;
    
    static class B{
        int value;
        final int get(){
            return value;
        }
    }
    
    public void foo(){
        y = b.get();
        //...
        z = b.get();
        sum = y + z;
    }
}
  1. 方法内联
  • 先采用方法内联。主要目的有两个,一个是去除方法调用的成本(如查找方法版本、建立栈帧等);二是为其他优化建立良好的基础。(编译器一般会把内联优化放在优化序列最靠前的位置)
public void foo(){
    y = b.value;
    //...
    z = b.value;
    sum = y + z;
}
  1. 冗杂访问消除
  • 假设代码中间的省略号所代表的操作,不会改变b.value的值。
  • 那么就可以把z = b.value 变成 z = y。(就可以不再去访问对象b的局部变量)
  • 如果把b.value看成是一个表达式,也可以看成一种公共子表达式消除。
//冗杂访问消除
public void foo(){
    y = b.value;
    //...
    z = y;
    sum = y + z;
}
  1. 复写传播
  • 逻辑中没有必要使用额外的变量z,它与变量y完全相同,所以可以用y来代替z。
//复写传播
public void foo(){
    y = b.value;
    //...
    y = y;
    sum = y + y;
}
  1. 无用代码消除
  • 完全没有意义的代码或者是永远不会被执行的代码也可以被删除。
public void foo(){
    y = b.value;
    //...
    sum = y + y;
}

3.1 方法内联

- 方法内联是编译器最重要的优化手段

  • 他可以消除方法调用的成本,也可以为其他优化手段建立基础。
public static void foo(Object object){
    if(object != null){
        System.out.println("do something");
    }
}
public static void testInline(String[] args){
    Object obj = null;
    foo(obj);
}
  • 例子中的testInline里面的代码都是无用代码,但是如果不做内联的话,就无法消除这些无用代码。

为什么说方法内联的过程不容易?

  1. 因为除了非虚方法以外,虚方法调用都必须在运行时进行方法接收者的多态选择,它们可能存在多余一个版本的方法接收者。Java中默认的实例方法都是虚方法
  2. 对于虚方法,编译器静态地去做内联的时候很难确定使用哪个版本

3.2 逃逸分析

  • 基本原理:分析对象动态作用域,当一个对象在方法里面被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中。(方法逃逸)。甚至还有可能被外部线程访问到,例如赋值给可以在其他线程中访问的实例变量。(线程逃逸)
  • 如果能证明一个对象不会逃逸到方法或线程之外,或者逃逸程度较低,则能为这个对象实例采取不同程度的优化。(例如可以将这个对象从堆上分配,改成在栈上分配,对象所占用的内存空间就会栈帧出栈而销毁。)

3.3 公共子表达式消除

  • 如果一个表达式E已经被计算过了,并且从先前计算到现在E中所有变量没有发生变化,那么E这次出现成为公共子表达式
    - 可以直接用前面计算过的表达式结果代替E。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/786465.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MATLAB绘图】

MATLAB绘图函数:Plot函数详解 介绍 MATLAB是一种常用的科学计算和数据可视化工具,它提供了强大的绘图函数,使用户能够创建各种类型的图表和图形。 基本语法 plot函数的基本语法如下: plot(x, y)其中,x和y是长度相…

HDFS的文件块大小(重点)

HDFS 中的文件在物理上是分块存储 (Block ) , 块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在Hadoop2.x/3.x版本中是128M,1.x版本中是64M。 如果一个文件文件小于128M,该文件会占…

Git 命令行教程:如何在 GitLab 中恢复已删除的分支

在软件开发过程中,版本控制是一个至关重要的环节。Git 是最流行的分布式版本控制系统之一,它能够帮助团队高效地管理代码。然而,有时候会发生意外,例如代码误合、错误的删除等情况,导致重要的开发分支本地和远程不慎被…

vue2踩坑之项目:v-if/else branches must use unique keys.

error: v-if/else branches must use unique keys. if 与 else 的 key 不能相同&#xff0c;在else标签里的key逐步加1 // if 与 else 的 key 不能相同 <div v-for"(item, index) in menuList" :key"item.id"><div v-if"item.name" :k…

js 操作符 in 的使用

1、判断对象中是否有某个属性&#xff0c;返回true/false let person {name: "小明", age: 18, year: 1998}; if ("age" in person){ //属性名必须是字符串形式&#xff0c;因为age不是一个变量console.log("person对象中含有age属性") } els…

(六)如何使用FLUX语言的文档

以下内容来自 尚硅谷&#xff0c;写这一系列的文章&#xff0c;主要是为了方便后续自己的查看&#xff0c;不用带着个PDF找来找去的&#xff0c;太麻烦&#xff01; 第 6 章 如何使用FLUX语言的文档 6.1 如何查看函数文档 1、这是FLUX语言的文档 https://docs.influxdata.com…

(七)FLUX查询InfluxDB

以下内容来自 尚硅谷&#xff0c;写这一系列的文章&#xff0c;主要是为了方便后续自己的查看&#xff0c;不用带着个PDF找来找去的&#xff0c;太麻烦&#xff01; 第 7 章 FLUX查询InfluxDB 7.1 前言 1、本节内容较为重要 7.2 FLUX查询InfluxDB的语法 1、使用FLUX语言查询…

AbstractMethodError: com.xx.serviceImpl.xxx method is abstract

今日一语&#xff1a; 其实我们没有必要和其他人进行比较&#xff0c;我们要比较的是昨天的自己 只有这样才能得到救赎和解脱&#xff0c;否则就是泥潭中跳跃&#xff0c;山谷中呐喊 在翻阅其他博主的博客时&#xff0c;似乎大多分享的是因为数据源驱动或者中间件的版本太高或者…

SpringCloud - 狂神学习笔记

1. 常见面试题 1.1 什么是微服务&#xff1f; 1.2 微服务之间是如何独立通讯的&#xff1f; 1.3 SpringCloud 和 Dubbo有那些区别&#xff1f; 1.4 SpringBoot 和 SpringCloud&#xff0c;请谈谈你对他们的理解 1.5 什么是服务熔断&#xff1f;什么是服务降级&#xff1f;…

微调模型来完成热狗识别的图像分类任务

我们来实践一个具体的例子&#xff1a;热狗识别。将基于一个小数据集对在ImageNet数据集上训练好的ResNet模型进行微调。该小数据集含有数千张热狗或者其他事物的图像。我们将使用微调得到的模型来识别一张图像中是否包含热狗。 首先&#xff0c;导入实验所需的工具包。 impo…

“铸网-2023” | 持续保障江西省实网应急演练

​​日前&#xff0c;由江西省工业和信息化厅主办&#xff0c;江西省网络安全研究院承办&#xff0c;南京赛宁信息技术有限公司协办并提供全程技术支撑的“铸网-2023”江西省工业领域网络安全实网应急演练在江西南昌圆满收官。 一、应急演练43天 赛宁持续助推工业企业应急能力…

论文精度系列之详解图神经网络

论文地址:A Gentle Introduction to Graph Neural Networks 翻译:图表就在我们身边;现实世界的对象通常根据它们与其他事物的连接来定义。一组对象以及它们之间的连接自然地表示为图形。十多年来&#xff0c;研究人员已经开发了对图数据进行操作的神经网络&#xff08;称为图神…

二叉树题目:从根到叶的二进制数之和

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;从根到叶的二进制数之和 出处&#xff1a;1022. 从根到叶的二进制数之和 难度 3 级 题目描述 要求 给你二叉树…

vue权限按钮的实现

鉴权函数 由于下面几种方式都需要用到鉴权函数&#xff0c;所以将其放置在组件外面&#xff0c;供组件或其他文件调用。 // src/utils/hasPermission.jsimport { usePermissionStore } from /stores import array from lodash/array export const hasPermission (value, def…

火车头采集文章批量伪原创【php源码】

火车头采集是一款基于Python语言开发的网络爬虫工具&#xff0c;用于快速高效地从互联网上采集数据并存储到本地或远程数据库。它简单易用且功能强大&#xff0c;在各行各业广泛应用。 火车头采集器AI伪原创PHP源码&#xff1a; <?php header("Content-type: text/h…

C# WPF项目创建(基于VS 2019介绍)

1.打开VS&#xff0c;选择《创建新项目》 2.选择《WPF应用程序》&#xff0c;如图 3. 项目名称根据需求自行命名&#xff0c;这边以“WpfApp1”来命名&#xff0c;位置自行选择&#xff0c;这边选择了"E:\test"&#xff0c;如图所示&#xff0c;“将解决方案和项目…

【广州华锐互动】VR模拟灭火逃生体验系统

VR模拟灭火逃生体验系统由广州华锐互动开发&#xff0c;是一种基于虚拟现实技术的应急演练与培训系统&#xff0c;可以真实模拟消防逃生场景&#xff0c;让体验者在沉浸式的虚拟环境中&#xff0c;根据正确的消防逃生方法提示&#xff0c;进行自救演练。这种科学普及方法是更加…

datafree KD CVPR2023 学习笔记(Abstract)

这个 是摘要的前部分 摘要 简单的提及 无数据的蒸馏 是怎么样的 和普通的蒸馏有一个本质的区别&#xff1a;没有训练数据 很火啊 最近 在对抗性的蒸馏框架中呢 存在一个问题 由于多个生成器生成的 非平稳分布的pseudo-samples 导致了学生网络的性能不好 提出一个解决方案的i…

Docker——数据管理与网络通信

Docker——数据管理与网络通信 一、Docker 的数据管理1&#xff0e;数据卷2&#xff0e;数据卷容器 二、端口映射三、容器互联&#xff08;使用centos镜像&#xff09;四、Docker 镜像的创建1&#xff0e;基于现有镜像创建1.1 首先启动一个镜像&#xff0c;在容器里做修改1.2 然…

如何搭建使用dubbo-Admin?

dubbo-Admin介绍 一款用于dubbo可视化界面操作的管理平台 dubbo-Admin特点 dubbo-Admin是dubbo的管理界面平台&#xff0c;且是一个前后端分离的项目&#xff0c;前端使用vue&#xff0c;后端使用springboot。 软件下载 dubbo-admin-0.5.0.zip 软件使用