什么是c语言执行的最小单位

  1. Java的编译只会生成字节码文件,而不会生成汇编(更不会到机器语言)。Java程序运行时,字节码文件会装载入java虚拟机,虚拟机将字节码“翻译”成机器指令来运行。java在不同平台上实现虚拟机,针对虚拟机编译就可以实现代码可移植性。
  2. C/C++程序编译执行过程简单来说,整个过程分为四个阶段:预处理(Pre-Processing)、编译(Compilation)、汇编(Assembling)、链接(Linking)。C/C++语言程序编译成的是机器码,通常不能在不同指令系统的机器上运行。C/C++程序的编译一般是直接针对硬件的。

前言:名词解释

机器码

定义:各种用二进制编码方式表示的指令,叫做机器指令码。

特点

  • 能够被计算机理解和接受,其编写的程序输入到计算机中,CPU可直接读取运行,因此执行速度是最快的;
  • 其与CPU紧密相关,不同类型的CPU对应的机器码也不同;

指令

由于机器码是有0和1组成的二进制序列,可读性太差,于是指令出现了。

定义:指令就是把机器码中特定的0和1序列,简化成相应的指令(一般使用英文简写,如mov,inc等),告诉计算机从事某一特殊运算的代码。如:数据传送指令、算术运算指令、位运算指令、程序流程控制指令、串操作指令、处理器控制指令。

组成形式:

一条指令通常由两个部分组成:操作码+地址码。

  • 操作码:指明该指令要完成的操作的类型或性质,如取数、做加法或输出数据等。
  • 地址码:指明操作对象的内容或所在的存储单元地址。

特点

  • 指令是计算机运行的最小的功能单位
  • 不同的硬件平台的同一种指令(比如mov),对应的机器码也可能不同。

指令集

定义:一台计算机上全部指令的集合,就是这台计算机的指令系统。指令系统也称指令集,是这台计算机全部功能的体现。

特点

  • 不同的硬件平台,各自支持的指令,是有差别的。因此每个平台所支持的指令,称之为对应平台的指令集。
  • 如常见的 x86指令集,对应的是x86架构的平台 ARM指令集,对应的是ARM架构的平台

汇编语言

概念:汇编语言是一种低级语言,亦称为符号语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。

特点

  • 在不同的硬件平台中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。
  • 由于计算机只认识指令码,所以用汇编语言编写的程序还必须翻译成机器指令码,计算机才能识别和执行。

高级语言

概念:高级语言是一种独立于机器,面向过程或对象的语言。

特点

  • 用人们更易理解的方式编写程序,编写的程序称之为源程序。
  • 高级语言与计算机的硬件结构及指令系统无关,它有更强的表达能力,可方便地表示数据的运算和程序的控制结构,能更好的描述各种算法,而且容易学习掌握。
  • 当计算机执行高级语言编写程序的时候,仍然需要将程序解释和编译成机器的指令码。完成这个过程的程序就叫做解释程序或者编译程序。

字节码

概念:字节码是一种特殊状态【中间码】的二进制代码文件,比机器码更抽象,需要转译后才能形成机器码。

特点

  • 字节码主要为了实现特定软件运行和软件环境、与硬件环境无关→【跨平台】
  • 字节码的实现方式是通过编译器和虚拟机器。编译器将源码编译成字节码,特定平台上的虚拟机器将字节码转译为可以直接执行的指令。

字节码典型的应用为:Java bytecode

什么是c语言执行的最小单位

虚拟机&物理机

“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行的能力。

区别

  • 物理机的执行引擎是建立在处理器、缓存、指令集和操作系统层面上的。
  • 虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件的制约指令集和执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。

前端编译器&后端编译器

前端编译器:把*.java文件转变成*.class文件的过程。

后端编译器:把Class文件转换成与本地基础设施(硬件指令集、操作系统)相关的二进制机器码的过程。

JVM之执行引擎

执行引擎是Java虚拟机核心组件之一,由于字节码并不能够直接运行在操作系统之上(字节码指令并非等价于本地机器指令,它内部包含的仅仅只是一些能够被JVM所识别的字节码指令、符号表、以及其他信息),因此JVM将字节码加载到其内部之后,执行引擎(Execution Engine)的任务就是将字节码指令解释/编译为对应平台的本地机器指令,简单来说JVM的执行引擎充当了高级语言翻译为机器语言的译者

执行引擎是如何工作的?

  1. 执行引擎在执行的过程中究竟需要执行什么样的字节码指令完全依赖于PC寄存器;
  2. 每当执行完一项指令操作之后,PC寄存器就会更新下一条需要被执行的指令的地址;
  3. 当然方法在执行的过程中,执行引擎可能会通过存储在局部变量表中的对象引用准确定位到存储在Java堆区中的对象的实例信息,以及通过对象头中的元数据指针定位到目标对象的类型信息;

什么是c语言执行的最小单位

JVM执行引擎具体流程图如下图所示

什么是c语言执行的最小单位

  • Java虚拟机的执行引擎的输入、输出都是一致的
  • 输入:字节码二进制流;
  • 输出:解释器和编译器将字节码”翻译“后的机器指令

提出问题:为什么说Java是半编译半解释型语言?你会在下面的内容中找到对应的答案

什么是c语言执行的最小单位

解释器

概念:当Java虚拟机启动的时候会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容“翻译”为对应平台的本地机器指令执行。(一行一行解释字节码指令,立即执行,不需要编译)

如何工作

  • 当一条字节码指令被解释执行完成之后,接着再根据PC寄存器中记录的下一条需要被执行的字节码指令执行解释操作。

在Hotspot VM中,解释器主要由Interpreter模块和Code模块构成

  • Interpreter模块:实现了解释器的核心功能
  • Code模块:用于管理Hotspot VM 在运行时生成的本地机器指令

由于解释器在设计上和实现上非常简单,如今基于解释器执行已经是低效的代名词。为了解决这个问题,即时编译技术出现了。

即时编译器(JIT)

Java语言的“编译器”在没有具体上下文语境的话,是一个很模糊的概念,因为它可能是指

  • 前端编译器(其实也叫 编译器的前端):把 .java 文件转换成 .class 文件的过程
  • 后端编译器(JIT编译器 Just In Time Compiler) :把字节码转换为机器码的过程
  • 静态提前编译器(AOT编译器 Ahead Of Time Compiler):直接把 .java 文件编译成本地机器码的过程

而JVM执行引擎中的即时编译器是属于后端编译器,因此下面我们主要以讲解即时编译器为主。

Hotspot虚拟机采用解释器和即时编译器并存的架构,在其运行的时候,会找到解释器和即时编译器相互合作的节点。基于这个特点,Java的运行性能已经可以和C/C++程序一教高下的地步。

问题来了:既然Hotspot VM中已经内置了JIT编译器了,那么为啥还需要再使用解释器来“拖累”程序的执行性能呢?

解释器与编译器两者各有优势:

  • 当程序需要迅速启动和执行的时候,解释器可以首先发挥作用【响应快】,不必等待即时编译器全部编译完再执行,可以立即运行。
  • 当程序启动后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译为本地代码,这需要一定的时间。但是编译为本地代码后,执行效率高。

综上所述,解释器还可以作为编译器激进优化时后备的“逃生门”,即让编译器根据概率选择一些不能保证所有情况都正确,但大多数时候都能提升运行速度的优化手段,当激进优化的假设不成立时(比如加在了新类以后,类型继承结构出现变化等)可以通过逆优化退回到解释状态继续执行,因此二者经常是相辅相成地配合工作。交互关系如下所示

什么是c语言执行的最小单位

HotSpot虚拟机内置了两个(或三个)即时编译器。

  • Client Compiler(客户端编译器/C1编译器) C1编译器会对字节码进行简单和可靠的优化,耗时短以达到更快的编译速度
  • Server Compiler(服务端编译器/C2编译器) C2进行耗时较长的优化,以及激进优化,但是优化的代码执行效率高。
  • Graal编译器:JDK10才出现的,目的是代替C2,这里不予讲解。

C1和C2编译器不同的优化策略

  • C1编译器有方法内联,去虚拟化、冗余消除 方法内联:将引用的函数代码编译到引用点处,这样就可减少栈帧的生成,减少参数的传递和跳转过程 去虚拟化:对唯一的实现类进行内联 冗余消除:在运行期间会把一些不会执行的代码折叠掉
  • C2的优化主要是在全局层面,逃逸分析师优化的基础,基于逃逸分析在C2上有如下几种优化 标量替换:用标量替换聚合变量 栈上分配:对于为逃逸的对象分配对象的在栈而不是在堆 同步消除:清除同步动作,通常指的是synchronized

注意:64位版本的JDK只支持”-server”模式,其它版本JDK,用户可以使用”-client”或”-server”参数强制指定虚拟机运行在客户端模式还是服务端模式。

  • 程序解释执行(不开启性能监控)可以触发C1,将字节码编译成机器码,可以进行简单优化,也可加上性能优化,C2编译会根据性能监控信息进行激进优化
  • 不过在Java7版本之后,一旦开发人员在程序中显示指定命令 “-server”时,默认开启,使用c1和c2共同执行

分层编译策略

分层编译工作模式出现以前,HotSpot虚拟机通常是采用解释器和其中一个编译器直接搭配的方式工作。为了在程序启动响应速度与运行效率之间达到最佳平衡,HotSpot虚拟机在编译子系统中加入了分层编译策略:

  • 第 0 层:程序解释执行,默认开启性能监控功能(Profiling),如果不开启,可触发第二层编译;
  • 第 1 层:可称为 C1 编译,将字节码编译为本地代码,进行简单、可靠的优化,不开启 Profiling;
  • 第 2 层:也称为 C1 编译,开启 Profiling,仅执行带方法调用次数和循环回边执行次数 profiling 的 C1 编译;
  • 第 3 层:也称为 C1 编译,执行所有带 Profiling 的 C1 编译;
  • 第 4 层:可称为 C2 编译,也是将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。

虚拟机执行模式

缺省情况下 Hotspot 虚拟机使用解释器与编译器并存的架构,开发人员也可以对其进行调整,设置为完全采用解释器或者完全采用即时编译器。

  • -Xint:完全采用解释器模式执行程序
  • -Xcomp:完全采用即时编译器模式执行程序,如果编译出现问题,解释器仍然会介入
  • -Xmixed:采用解释器+即时编译器混合模式执行程序

C:\Users\13832>java -version java version "1.8.0_162" Java(TM) SE Runtime Environment (build 1.8.0_162-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode) C:\Users\13832>java -Xint -version java version "1.8.0_162" Java(TM) SE Runtime Environment (build 1.8.0_162-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, interpreted mode) C:\Users\13832>java -Xcomp -version java version "1.8.0_162" Java(TM) SE Runtime Environment (build 1.8.0_162-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, compiled mode) 复制代码

上面提到了热点代码,什么是热点代码?如何确定代码是热点代码的呢?请继续向下阅读。

热点代码&探测方式

JIT编译器需要根据字节码执行的频率来确定是否要将字节码编译成本地机器指令,执行频率较高的代码就称为热点代码,JIT编译器就针对这些执行频率较高的代码进行深度优化,编译成本地机器指令,在下次执行时就不用再使用解释器解释了,而是直接执行本地机器指令,进而提升JAVA性能。

热点代码主要有两类:

  • 被多次调用的方法
  • 被多次执行的循环体

对于这两种情况,编译的目标对象都是整个方法体。由于这种编译方式发生在方法的执行过程中,因此也被称为栈上替换。或者简称为 OSR(On Stack Replacement),即方法的栈帧还在栈上,方法就被替换了。

上面的描述中,一个方法究竟要调用多少次,或者一个循环体究竟循环多少次,才会达到这个标准?这就依赖热点探测功能(目的是确定某段代码是不是热点代码,是不是需要触发即时编译)。

主流的热点探测判定方式有两种,分别是:

  • 基于采样的热点探测:虚拟机会周期性地检查各个线程地调用栈顶,如果发现某个(或某些)方法经常出现在栈顶,那么该方法即为“热点方法”。这种方法实现简单高效,但很难精确地确认一个方法地热度。
  • 基于计数器的热点探测:虚拟机会为每个方法(甚至是代码块)建立计数器,统计方法的执行次数,如果执行次数超过一定的阈值就认为它是“热点方法”。【HotSpot虚拟机使用的方式】

采用计数器的热点探测,Hotspot VM 将会为每一个方法都建立2个不同类型的计数器,分别为方法调用计数器(Invocation Counter)和回边计数器(Back Edge Counter)

  • 方法调用计数器用于统计方法被调用的次数
  • 回边计数器则用于统计循环体执行的循环次数

1)方法调用计数器

  • 这个计数器就是用于统计方法被调用的次数,它的默认阈值再 Client 模式下是1500次,再Server下是10000次,超过这个阈值,就会触发JIT编译。这个阈值可以通过虚拟机参数 -XX:ComplieThreshold 来设定
  • 当一个方法被调用的时候,会先检查该方法是否存在被JIT编译过的版本,如果存在,则优先使用编译后的本地代码来执行;如果不存在已经被编译的版本,则将此方法的调用计数器值加1,然后判断方法调用计数器和回边调用计数器之和是否超过方法调用计数器的阈值,如果超过,就向编译器提交一个该方法的编译请求

热度衰减概念:方法调用计数器统计的不是被调用的绝对次数,而是一个相对的执行频率。即一段时间之内方法被调用的次数。当超过一定的时间限制,如果方法调用的次数不足以将它转交给即时编译器编译,那这个方法的调用计数器就会减少一半,这个过程就是调用计数器热度的衰减(Counter Decay),而这段时间就称为次方法统计的半衰周期(Counter Half Life Time)。

进行热度衰减的动作,是在虚拟机内部垃圾收集的时候顺便执行的,可以使用虚拟机参数 -XX:-UseCouinterDecay关闭热度衰减,这样只要系统运行时间足够长,程序中绝大部分方法都会被编译成本地代码。

  • 可以使用 -XX:CounterHalfLifeTime参数设置半衰周期的时间,单位是秒。

什么是c语言执行的最小单位

2) 回边计数器

  • 统计方法中循环体代码的执行次数,建立回边计数器统计就是为了触发栈上的替换编译。
  • 当解释器遇到一条回边指令时,会先查找将要执行的代码片段是否有已经编译好的版本,如果有的话,将会优先执行已编译的代码,否则就把回边计数器的值加1,然后判断方法调用计数器与回边计数器值之和是否超过回边计数器的阈值。超过阈值的话,将会提交一个栈上替换编译请求,并把回边计数器的值降低一些。

什么是c语言执行的最小单位

代码演示

public class IntCompTest { public static void main(String args) { long start = System.currentTimeMillis(); testPrimeNumber(1000000); long end = System.currentTimeMillis(); System.out.println("花费的时间为:" + (end - start) + "ms"); } public static void testPrimeNumber(int count){ for (int i = 0; i < count; i++) { //计算100以内的质数 label:for(int j = 2;j <= 100;j++){ for(int k = 2;k <= Math.sqrt(j);k++){ if(j % k == 0){ continue label; } } } } } } -Xint:花费的时间为:6184ms -Xcomp:花费的时间为:746ms -Xmixed:花费的时间为:710ms 复制代码

Graal编译器&AOT编译器

Graal编译器

  • 在JDK10之后,Hotspot又加入了一个全新的即时编译器:Graal 编译器,目标是在未来替代C2编译器
  • 目前还在实验阶段 -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler去激活才能使用

AOT编译器

  • JDK9.0之后加入了AOT编译器(静态提前编译器 Ahead Of Time Compiler)
  • 所谓的AOT编译器时与即时编译器对立的一个概念,即时编译器在程序运行的时候,而AOT编译器是在程序运行之前,便将字节码转换为机器码
  • 好处: 可以直接执行,不必等程序预热,减少第一次运行慢的体验
  • 缺点: 破坏了Java”一次编译,到处运行“,因为直接编译之后的文件是固定的,必须为每种系统都编译 降低了Java动态链接的动态性,加载的代码在编译器期就必须全部已知 还需要继续优化中,最初只支持Linux x64 java base

本文【什么是c语言执行的最小单位】由作者: 前端后端 提供,本站不拥有所有权,只提供储存服务,如有侵权,联系删除!
本文链接:https://www.cuoshuo.com/blog/4146.html

(0)
上一篇 2023-03-09 08:31:01
下一篇 2023-03-09 08:52:33

相关推荐

  • linux查看进程启动时间_linux查看机器启动时间

    有个网友来求助说,在linux操作系统中怎么查看机器什么时候关机的、什么时候重启的以及机器开机运行了多久呢?个人感觉Linux的查看方法要比Windows的方便又直观很多,我们可以利用last命令查看关机时间,该命令用于显示用户最近登录信息,当我们把参数设置为“-x shutdown”时,就可以显示系统的关机日期及时间。 本教程操作环境:centos7系统、…

    2023-03-10
    500
  • 内存使用率高会怎么样_内存到底影响什么

    用安卓系统的朋友会经常遇到手机开机后就占用了绝大多数系统内存的尴尬局面。 为了降低手机内存耗费,绞尽脑汁,习惯了是不久就优化一下,清理一下,结束下进程。是否想过一个问题,是我们做的不对还是手机本来就这样挺好呢? 重启了下手机,什么都没开,又优化了下,系统内存使用率还是在50%左右。 内存使用率高原因之一 安装了过多软件,开机自动启动。 很多软件安装后,都会默…

    2023-03-15
    000
  • 火车票自动刷票软件叫什么(自动抢高铁票用什么软件好)

    还有两个月,春节就要到了,能否抢到回家的火车票成为很多人的心头病。如今有了好消息!据媒体报道,中国铁路客票发售和预订系统研发的技术带头人单杏花透露,她和团队研发的“候补购票”功能将于2019年春运期间上线,届时抢票情况将会再次得到缓解。 支付预购资金 软件将自动购票 2019年春运期间,旅客如果遇到车票售完的情况,在12306平台登记购票信息支付预购票资金后…

    2023-03-15
    000
  • 某高校学生档案管理系统

    本期主编:星辰:高校档案管理系统有哪些功能? 随着现在的教育水平上涨,各高校的招生人数也在不断地增加,学生的数量也是空前壮大。那么高校的档案工作将会迎来新的挑战。那档案管理难怎么办呢? 别急,科技的创新也为管理工作带来了新型的工具“档案管理系统”,那么系统到底有哪些功能呢?可以帮助我们做到哪些呢?今天就给大家分享一下,记得收藏喔。 往期也分享了关于档案管理的…

    2023-03-20
    000
  • vc++6.0怎么运行快捷键

    Microsoft Visual C++6.0作为适合新手编写C语言的编程软件,被大家广为使用。然而初次使用此软件的同学即使是中文版的也完全摸不到头脑,完全不知道如何使用它,接下来我将介绍如何用Microsoft Visual C++6.0编写程序。 首先,点击【文件】选择【新建】选择文件中的【C++ Source File】输入要创建的【文件名】以及选择要…

    2023-03-13
    300
  • 织梦手机端模板在哪里_织梦本地安装教程

    说明: 首先说明下,本站下载的织梦源码都是带后台程序的,是目前织梦的最新版,大家不用再去官方下载,直接安装使用即可。 安装步骤: 首先,要明确自己的空间是否支持PHP+Mysql 第一步:将本站下载的源码解压后传到空间或者本地服务器 注意:(由于有很多人反应安装后首页样式都乱的,所以强烈要求安装到根目录,如:127.0.0.1 / www.xxx.com,或…

    2023-03-18
    200
  • 爱尔朗分布期望与方差的关系

    概率可以得知某些事件发生的可能性大小,但概率并非万能,它无法指出所发生的这些事情的整体影响,也无法指出这种整体影响对人的具体影响。这个时候就需要使用到期望了,期望的作用在于利用概率预测长期结果,以及量度这些预测结果的确定性。 什么是期望 在概率论和统计学中,一个离散性随机变量的期望是试验中每次可能结果的概率乘以其结果的总和。换句话说,期望是随机试验在同样的机…

    2023-03-15
    000
  • ubuntu安装flash player

    看到这篇文章说明你已经从老版本升级到 Ubuntu 16.04 或进行了全新安装,在安装好 Ubuntu 16.04 LTS 之后建议大家先做如下 15 件事。无论你是刚加入 Ubuntu 行列的新用户,还是有经验的老用户,你都会发现一些非常有用的调整和建议。 1.了解Ubuntu 16.04 LTS新特性 新选项!新应用程序!新内核!新的…… 所有东西都是…

    2023-03-21
    000
  • c语言入门自学零基础电子书

    每天一个C语言小项目,提升你的编程能力! 贪吃蛇游戏大家应该都不陌生了,要说没玩过的话,可能你是15后吧? 贪吃蛇游戏最初为单机模式,后续又陆续推出团战模式、赏金模式、挑战模式等多种玩法。 用游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴…

    2023-03-10
    200
  • nginx配置文件参数详解 nginx详细配置教程

    nginx 文件结构 … # main全局块 events { #events块 … } http #http块 { … #http全局块 server #server块 { … #server全局块 location #location块 { … } location { … } } …

    2023-03-15
    100

发表回复

登录后才能评论
返回顶部
错说博客上线啦!