我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JAVA虚拟机(JVM)详细介绍(七)——JVM优化

短信预约 信息系统项目管理师 报名、考试、查分时间动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JAVA虚拟机(JVM)详细介绍(七)——JVM优化

20190621172513514.png

还以这个图为例,从.java到.class是编译过程,从.class到机器码是解释过程。下面对其进行分别优化。在优化过程中,对编译阶段的优化主要是对前端编译器的优化,在运行阶段的优化,主要是对即时编译器的优化。

2019062117255488.png

编译器优化

编译过程

20190621172714334.jpg

以上为javac的编译过程图,以下为javac编译过程的主体代码。

20190621174151194.jpg

下面对其步骤进行详细解读
1、解析与填充符号表

词法分析

将源代码的字符流转变为标记(Token)集合,标记是编译过程中的最小元素,如a,=,b,int。

语法分析

根据Token序列构造抽象语法树。以后编译器基本不会再对源码文件进行操作了,后续的操作都是建立在抽象语法树上。抽象语法树是一种用来描述程序代码语法结构的树形表示方式,节点代表代码中的一个语法结构,例如修饰符,返回值等。

填充符号表

符号表是由一组符号地址和符号信息构成的表格,用于编译的不同阶段。如在语义分析中,用于语义检查和产生中间代码;在目标代码生成阶段,用于地址分配的依据。

2、注解处理器
这部分是插入式注解处理器在编译期间对注解进行处理的过程。其可以对语法树进行修改,一旦进行了修改,编译器将回到上面的第一步进行重新处理,每一次循环称为一个Round,也就是上图中的回环过程。

3、语义分析与字节码生成
在经过语法分析后,生成的语法树是一个结构正确的源程序的抽象,但无法保证源程序是符合逻辑的。语义分析的任务是对结构上正确的源程序进行上下文有关性质的审查。比如下面代码中的错误只能在语义分析阶段检查出来。

boolean a=false;
char b=2;
int c=a+b

此阶段包括如下4个步骤:

标注检查

变量使用前是否已被声明、变量与赋值之间的数据类型是否能够匹配等。还有一个常量折叠,即把a=1+2变为a=3。所以在代码中的a=1+2和a=3并不会增加程序运行期cpu指令的运算量。

数据及控制流分析

检查程序局部变量在使用前是否有赋值,方法的每条路径是否都有返回值,是否所有的受查异常都被正确处理了等问题。在类加载时也有一个数据及控制流分析,其目的基本是一致的,但校验的范围不同,有些校验项只有在编译期或运行期才能运行。

解语法糖

语法糖是在计算机语言中添加某种语法,其对语言的功能没有影响,但是能提高程序的可读性。语法糖包括泛型,自动拆装箱等。虚拟机运行时不支持这些语法,它们在编译阶段还原回基础语法结构。这个过程称为解语法糖。

字节码生成

将之前步骤生成的信息(语法树、符号表)转化成字节码写到磁盘中,然后添加和转换了少量的代码。如把字符串的加操作替换为StringBuffer或StringBuilder的append()操作。

至此,Class文件生成了。

语法糖

语法糖是java中添加某种语法,对语言的功能没有影响,但是可以增加程序的可读性。包括泛型、内部类、枚举类等。

泛型与类型擦除
泛型可用于类、接口和方法的创建中,用于对放入集合元素的类型的约束。泛型只在程序源码中存在,在编译阶段有解语法糖的步骤,所以在.Class文件中,已经变为了原来的原生类型了。这个过程叫做类型擦除。
泛型擦除前:

public static void main(String[] args){
    Map map=new HashMap<>();
    map.put("姓名","小明");
    map.put("性别","男");
    sout(map.get("姓名"));
    sout(map.get("性别"));
}

泛型擦除后:

public static void main(String[] args){
    Map map=new HashMap();
    map.put("姓名","小明");
    map.put("性别","男");
    sout((String)map.get("姓名"));
    sout((String)map.get("性别"));
}

所以ArrayList和ArrayList在运行期时是同一个类。

自动拆装箱、循环遍历
这些是java中使用最多的语法糖。编译前:

public static void main(String[] args){
      List list=Arrays.asList(1,2,3,4);
      int sum=0;
      for(int i:list){
              sum +=i;
      }
      System.out.println(sum);
}

编译后:

public static void main(String[] args){
      List list=Arrays.asList(new Integer[] {
                Integer.valueOf(1),
                Integer.valueOf(2),
                Integer.valueOf(3),
                Integer.valueOf(4)});
      int sum=0;
      for(Iterator localIterator=list.iterator();localIterator.hasNext();){
                   int i=((Integer)localIterator.next()).intValue();
                   sum +=i;
      }
      System.out.println(sum);
}

可见,自动拆装箱在编译后被转化为了对应的包装和还原方法,如Integer.valueOf()和Integer.intValue()。
遍历循环则把代码还原为了迭代器的实现。

条件编译
根据布尔常量值的真假,编译器会把分支中不成立的代码块消除掉。

public static void main(String[] args){
      if(true){
            sout("block 1");
      }else{
           sout("block 2");
     }
}

编译后,代码变为:

public static void main(String[] args){
     sout("block 1");
}

运行期优化

一般情况下,我们将.java编译成.class,.class再解释成机器码。但是也有特殊的情况。有些代码调用比较频繁,比如某个方法或代码块的运行特别频繁,为了提高程序的执行效率,在运行时,虚拟机会把这个代码直接编译成机器码,并进行各种层次的优化。这样的代码称为热点代码。完成这个任务的编译器被称为即时编译器。但是其并不是虚拟机必需的部分。

20190621173045527.png

即时编译器的概述

(1)为什么虚拟机要使用解释器和编译器并存的架构?

虚拟机里包含着解释器和编译器。当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。在程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获取更高的执行效率。

当程序运行环境中内存资源限制较大,可以使用解释执行节约内存,反之可以使用编译来提升效率。

(2)为什么虚拟机要实现两个不同的即时编译器?

虚拟机中内置了两个即时编译器,分别为Client Compiler和Server Compiler,又称为C1和C2。

默认只使用其中的一个,至于选择哪个,取决于虚拟机会根据自身版本和宿主机器的硬件性能自动选择运行模式。用户也可以使用“-client”、“-server”进行指定。

(3)程序何时使用解释器执行?何时使用编译器执行?

虚拟机有一个分层编译策略。

第0层:程序解释执行,解释器不开启性能监控功能,可触发第1层编译

第1层:也称为C1编译,将字节码编译为本地代码,进行简单、可靠的优化,如有必要将加入性能监控的逻辑。

第2层:也称为C2编译,将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。

(4)哪些程序代码会被编译为本地代码?如何编译为本地代码?

热点代码包括如下两类,其均把整个方法作为编译对象。

a、被多次调用的方法

b、被多次执行的循环体

热点探测是用来判断一段代码是否为热点代码,其方式有两种:

a、基于采样

b、基于计数器。HotSpot使用的是这种。它为每个方法准备了两类计数器:统计方法被调用次数的方法调用计数器和统计一个方法中循环体代码执行次数的回边计数器。

(5)如何从外部观察及时编译器的编译过程和编译结果?

可以使用 -xx:+PrintCompilation 查看哪些方法被即时编译器编译了。

优化技术有哪些?

虚拟机的即时编译器在生成代码时,采用了如下的代码优化技术。

(1)公共子表达式消除

如果一个表达式E已经计算过了,那如果再次出现E时就不会再对它进行计算。比如:

int d=(a*b)*12+c+(c+b*a)

如果这段代码交给javac编译器,则不会进行任何优化。如果交给即时编译器,会被进行如下步骤的优化:

第一步:消除公共子表达式

int d=E*12+c+(c+E)

第二步:代数化简:

int d=E*13+c*2

(2)数组边界检查消除

数组边界检查是什么?
如果有一个数组foo[],在java语言中访问数组元素foo[i]的时候,系统将会自动进行上下界的范围检查,检查i是否满足0≤i≤foo.length这个条件。

那怎么进行消除呢?
a、把运行期检查提到编译期完成。如foo[3],只要在编译期根据数据流分析来确定foo.length的值,并判断下标“3”没有越界,执行的时候就不用判断了。
b、隐式异常处理。这种思路通常用于空指针检查和算符运算中除数为零的情况。

if(foo!=null){
  return foo.value;
}else{
  throw new NullPointException();
}

被隐式异常处理优化后,变为如下代码:

try{
  return foo.value;
}catch(segment_fault){
  uncommon_trap();
}

除了数组边界检查消除,还有自动装箱消除、安全点消除、消除反射等。

(3)方法内联

把目标方法的代码“复制”到发起调用的方法之中,避免发生真实的方法调用。

public int add(int x1, int x2, int x3, int x4) {  
        return add1(x1, x2) + add1(x3, x4);  
 }  

public int add1(int x1, int x2) {  
        return x1 + x2;  
    }

运行一段时间后JVM会把add1方法去掉,并把代码翻译成:

public int add(int x1, int x2, int x3, int x4) {  
        return x1 + x2 + x3 + x4;  
}

(4)逃逸分析

当一个对象在方法中被定义后,它可能被外部方法所引用,比如作为调用参数传递到其它方法中,这称为方法逃逸。同理,如果被外部线程访问到,它就称为线程逃逸。

对变量进行相应分析就叫做逃逸分析。如果能证明别的方法或线程无法通过任何途径访问到这个对象,则可以为这个变量进行一些优化。

优化的手段有栈上分配、同步消除、标量替换等。以同步消除为例,如果逃逸分析能够确定一个变量不会逃逸出线程,即无法被其它线程访问到,那对这个变量实施的同步措施就可以消除掉了。

以上内容便是关于JAVA虚拟机中JVM优化的全部介绍,更多相关问题请访问PHP中文网:JAVA视频教程

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JAVA虚拟机(JVM)详细介绍(七)——JVM优化

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JAVA虚拟机(JVM)详细介绍(七)——JVM优化

还以这个图为例,从.java到.class是编译过程,从.class到机器码是解释过程。下面对其进行分别优化。在优化过程中,对编译阶段的优化主要是对前端编译器的优化,在运行阶段的优化,主要是对即时编译器的优化。编译器优化编译过程以上为javac的编译过程图,以
JAVA虚拟机(JVM)详细介绍(七)——JVM优化
2017-09-20

JAVA虚拟机(JVM)详细介绍(一)——JVM概述

首先,对以上的四部分进行解释。(1)自动内存管理讲的是java运行时数据区里的部分,分为内存划分和垃圾收集器。(2)执行子系统讲的是画红圈的三部分:类文件结构、类加载机制、字节码执行引擎。(3)优化分别为编译期优化和运行期优化。(4)并发讲的是虚拟机是如何实现
JAVA虚拟机(JVM)详细介绍(一)——JVM概述
2016-06-30

JAVA虚拟机(JVM)详细介绍(八)——高效并发

内存模型内存模型是在特定的操作协议下,对特定的内存或高速缓存进行读写访问的过程抽象。其主要目标是定义程序中各个变量的访问规则。主内存和工作内存所有的变量都存储在主内存中,每条线程还有自己的工作内存,其工作内存中是被线程使用到的变量的主内存副本拷贝,线程对变量的
JAVA虚拟机(JVM)详细介绍(八)——高效并发
2017-08-31

JAVA虚拟机(JVM)详细介绍(五)——类加载机制

上篇中我们讲解了Class文件,这篇我们说说虚拟机是如何加载这些Class文件的?Class文件中的信息进入到虚拟机后会发生什么变化?这就涉及到了类加载机制。类加载机制是把类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚
JAVA虚拟机(JVM)详细介绍(五)——类加载机制
2015-12-28

JAVA虚拟机(JVM)详细介绍(四)——类文件结构

讲完了自动内存管理,我们来说说执行子系统。执行子系统讲解的是JVM如何执行程序。Class文件概述这篇我们只讲讲Class文件。Class文件又名类文件或字节码文件。javac将.java文件(源代码)编译成.class文件(字节码),jvm再将.class文
JAVA虚拟机(JVM)详细介绍(四)——类文件结构
2016-02-29

JAVA虚拟机(JVM)详细介绍(三)——垃圾收集机制

在上一篇中我们说过,自动内存管理分为两部分:给对象分配内存和回收分配给对象的内存。这篇我们说说后者,即回收分配给对象的内存。回收内存要用到垃圾收集机制,英文名儿是GC(Garbage Collection)。在本部分我们要解决如下几个问题:1、哪些内存需要回收
JAVA虚拟机(JVM)详细介绍(三)——垃圾收集机制
2017-01-27

JAVA虚拟机(JVM)详细介绍(六)——字节码执行引擎

JVM中的执行引擎在执行java代码的时候,一般有解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行)两种选择。栈帧定义:栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,它位于虚拟机栈里面。作用:每个方法从调用开始到执行完成的过程中,都
JAVA虚拟机(JVM)详细介绍(六)——字节码执行引擎
2014-07-03

Java虚拟机怎么利用JVM进行优化

本篇文章为大家展示了Java虚拟机怎么利用JVM进行优化,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。前言Java虚拟机是运行所有Java程序的抽象计算机,是Java语言的运行环境,它是Java 最
2023-05-31

JAVA虚拟机(JVM)详细讲解(二)——内存的划分

我们知道,在C++语言里,如果想使用一个对象,需要对其进行new操作;如果不用这个对象了,需要对其进行delete操作。一旦开发人员忘记写delete语句了,就会造成内存泄露。【内存被对象占用着不还,就叫内存泄露。】而java就聪明了,它从“手动”进化成了“自
JAVA虚拟机(JVM)详细讲解(二)——内存的划分
2020-08-19

JVM(Java虚拟机)详解(JVM 内存模型、堆、GC、直接内存、性能调优)

JVM(Java虚拟机) JVM 内存模型 结构图 jdk1.8 结构图(极简) jdk1.8 结构图(简单) JVM(Java虚拟机): 是一个抽象的计算模型。如同一台真实的机器,它有自己的指令集和执行引擎,可以在运行时操控内存区域。
2023-08-30

深入理解JVM虚拟机12:JVM性能管理神器VisualVM介绍与实战

微信公众号【Java技术江湖】一位阿里 Java 工程师的技术小站。作者黄小斜,专注 Java 相关技术:SSM、SpringBoot、MySQL、分布式、中间件、集群、Linux、网络、多线程,偶尔讲点Docker、ELK,同时也分享技术
2023-06-02

Java 虚拟机(JVM)之基本概念详解

1、类加载子系统:负责从文件系统或者网络中加载Class信息,加载的信息存放在一块称之为方法区的内存空间。2、方法区:就是存放类信息、常量信息、常量池信息、包括字符串字面量和数字常量等。方法区是辅助堆栈的块永久区,解决堆栈信息的产生,是先决
2023-05-31

JVM优化:虚拟机栈&本地方法栈

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。栈帧存储了方法的局部变量表、操作数 栈、动态连接和方法返回地址等信息。每一个方法从调用至执行完成的过程,都对应着一个栈帧在虚拟机栈里从入 栈到出栈的过程。

JVM(Java虚拟机)简介(动力节点Java学院整理)

一、概要1.Java虚拟机(Jvm)是什么?2.Java虚拟机是用来干什么的?3.Java虚拟机它的体系结构是什么样子的?4.Java虚拟机在工作做扮演什么角色?5.Java虚拟机在运行时数据区?二、Jvm基础概念Java虚拟机(Jvm)是
2023-05-31

JVM类加载机制及生命周期的详细介绍

这篇文章主要讲解了“JVM类加载机制及生命周期的详细介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JVM类加载机制及生命周期的详细介绍”吧!一.目标:1.什么是类的加载?2.类的生命周期
2023-06-02

如何进行JVM虚拟机中Java的编译期优化与运行期优化

这篇文章将为大家详细讲解有关如何进行JVM虚拟机中Java的编译期优化与运行期优化,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。java编译期优化java语言的编译期其实是一段不确定的操作过
2023-06-02

理解Java虚拟机(JVM):优化代码执行效率的内部机制

本文将深入理解JVM的内部机制,以及如何通过优化代码执行提高程序的性能。
虚拟机程序2024-11-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录