JVM之Java编译到执行(1)--引

news/2025/1/31 6:11:50/

Java语言特点

一次编写,到处运行。也就是跨平台。 因为这个跨平台的实现原理,而导致Java的编译流程,与以往的C++之类语言有不同。

各个操作系统的底层实现,资源的协调,和硬件操作各有各的不同。就意味着,如果按照早期使用C++这类语言写,每个系统都有不一样的API,不仅存在大量的API调用区分,而且那就要为每一个操作系统都要编译一次。说来简单,楼主做过这种工作,出bug的时候,会编译很多次,光编译这里,就要消耗不少精力。真的比较烦。

想要做到一次编写到处运行的话,Java采取的方案是,将程序员编写的代码首先优化为一个字节码文件,然后为每一个操作系统提供虚拟机,也就是JVM。 这个虚拟机里可以解释这个字节码文件,并将其生成相应系统可以识别的机器码。所以最简化的路子是下图所示。

这样的话有什么好处呢?

  • 只要字节码文件一样,JVM虚拟机又是专业的人提供的,可以保证上层调用的API是一致的。也可以保证得到良好的解析,最终生成各自系统可识别的机器码,并执行。
  • JVM虚拟机是被人提供的,就意味着,他们对这块的操作权是很大的,可以用顶级的智慧,顶级的开发人员,对各个系统的虚拟机之后进行不断的优化。不用程序员管。
  • 对于语言的支持方面,需要提供良好的API,这就意味着,API的开发操作权也在专业的公司手里。他们足可以按照比较先进的思想,提供比C++好用多得多的API。减少下游程序员的学习难度。

编译过程

Java语言的编译,因为上述的设计方案。会导致编译过程分为两个过程

  • 1 从源代码编译到字节码的环节 (称为前端编译)
  • 2 从字节码到可执行程序的环节 (称为后端编译,运行时做的工作)

其中前端编译,就是那种在计算机中输入一个javac指令,然后就编译成了class文件。在浅层的理解上,认为这就是编译完成了。事实上class文件它不能直接执行的,离执行还差的远。

这些class文件,在真正执行的时候,会让JVM去处理,这个时候属于运行时了已经。在运行时,JVM会拿到已经生成的class文件集,将这些文件里的一条条指令解释为相应平台可以识别的机器码。这样两种配合的情况下,我们写的代码才得以运行。

“解释”

解释型语言简述

解释型语言指的是程序不需要程序员进行编译,程序在运行时才会被翻译成机器码的那类语言。这就意味着,每次执行都得解释一次。因此这类语言有个普遍的缺陷,是效率较低。但是其优势就是跨平台性比较好,我们这里的跨平台烦恼,主要就是编译不同平台所带来的工作工时还有失误的消耗,这个是比较折磨开发者的。解释型是可以解决这种问题的。代表语言为:Python/JavaScript / Perl /Shell 等。 Java也算是。但又没那么彻底。

编译型语言简述

编译型语言的特点是,写的程序执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高。缺点就是,开发和维护成本高。其代表语言为 C C++。

解释器VS编译器

上图中有个环节,有一个叫解释器的部分。这块最开始是令我比较迷惑的。原因是我认为Java作为一个解释型语言,那直接解释就好喽。解释不就是编译么?为什么我看到书上,解释和编译要区分呢?为什么这个流程甚至是一边解释一边翻译呢?

原来这里面存在一个区别,解释器和编译器,是实现同一种目标的两种不同的工作方式。

解释器

解释器是直接执行用编程语言编写的指令的程序。它逐行读取源代码,将其转换为机器语言(或某种中间形式),然后立即执行。这意味着解释器在执行程序时,需要逐行解释代码,因此执行速度通常比编译器慢。

编译器

编译器则是将源代码整体转换(或“编译”)为机器语言或低级语言(如汇编语言)的程序。它首先会对源代码进行词法分析、语法分析、语义分析等,然后生成中间代码,并最终转换为机器代码。这个过程通常称为“编译”,生成的机器代码可以独立运行,无需解释器的支持。

前端编译

javac就是Java的前端编译器,是个编译工具,负责把程序员写的java文件,经过初步的分析,转换为class文件。 class文件就是字节码文件。二者可以一块理解。

Java的前端编译基本就是做了这个工作。它的编译流程不做赘述,相当于C++编译或者编译原理的打折版。什么词法,语法,语义分析。这个知识点探下去没完没了,是一个比较深的话题。略过。流程上图已经给出了可以翻上去看一些图片。

Java从编写代码到执行涉及到的编译器概览

我们重点注意的是下半部分,主要由JVM承担的,发生在运行时的后端编译工作!

Java严格的说是一个编译 + 解释混合的语言。这使得我们讨论Java编译到执行这个话题时,不止要讲静态的编译,还要深入了解Java是怎么执行代码的,比如,解释器一条条指令解释,那指令是哪儿来的?存哪里了?类加载环节是不是和这里有关呢?类加载究竟做了什么事?Class除了反射时用,JVM到底用它做什么了?为什么需要它?class文件里面好像有操作指令,这些指令是不是相当于C++可执行程序里的代码段呢?new一个对象JVM划分内存,那个垃圾回收机制是怎么管理这些对象的? 逐渐铺开发现相当于讲1/3JVM机制,一片文章根本讲不完。我会拆分下来一块一块讲。

JVM后端编译

后端编译流程图

对于Java解释字节码很粗略的流程,在上图已经画出来了。总共拆分为两个阶段。

  • 类加载 and 二进制转换
  • 解释器解释 和即时编译器优化同时进行。(为什么这样之后解释)
需求分析

在了解一个方案的解决办法前,有时候思考问题,要把事件重置到还未发生时考虑。有没有想过为什么JVM的后端编译器为什么要把流程搞成这样子?还什么类加载,还要解释器,那个JIT是啥?为什么要有这个?

我们不妨以一个实现者的视角来聊聊。假设你就是这个编译器的实现者

  • 你们的这个大工程中,你负责开发后端编译器这块的组件。你组件的输入内容已经确定了,是前端编译机器的产出--字节码文件,即字节码文件。
  • 你这个组件的产出结果是,生成机器码,能上机跑的那种。(我们排除掉一切更为复杂的需求,如内存回收等等机制)

那你会怎么解决呢?

我想是个人都得先分解输入内容和输出内容这两大关键点的样子吧。 于是乎

  • 1 你必须要从java语言设计的思想,和所有语言通用思想方面来考虑java语言的组成结构。并能做到很好的拆分转换优化。另外,有些代码调用到中级逃不过C语言或C++,他们的接口入口地址,您要怎么找,怎么正确的连接。等等等等一堆的问题。
  • 2 你必须要十分熟悉操作系统原理,尤其是一个程序要跑起来,计算机内部的状态究竟是什么样子。你需要将你输入的那些二进制代码,落实到运行时内存的数据里!
  • 3 锦上添花的其余功能,例如垃圾回收机制。

CPU如何执行程序

粗略的讲。CPU本质上是一个没有主见的, 沿着代码块内存一条一条机械执行的工具, 我们对代码块做了很多的编程, 保证操作指令和被操作数是正确的, 这样cpu识别这些指令,也能一条接一条执行.基本没有错误.

您编译代码的目的就是,把代码变成最终CPU识别的样子。

JVM的思路

JVM的思路就是,模拟这种场景。只不过“代码块内存”里的指令是class文件中描述的字节码指令。JVM模拟CPU的操作流程,也是一条一条往下“读”,像极了CPU执行指令那般。在“读”的过程中,JVM会通过编译器或者解释器,将这些字节码指令转换为真正的机器码。这样就达成了与CPU协议的一致。

JVM的整体流程开始于类加载,我们知道了JVM宏观的思路后,再研究每个环节,下篇文章将先从类加载讲起, 类加载的输入是class文件(字节码文件),楼主将贯彻费曼学习法,知无不言,将他们写出来。


http://www.ppmy.cn/news/1567802.html

相关文章

【设计模式】访问者模式(Visitor Pattern): visitor.visit(), accept()

访问者模式(Visitor Pattern)简介 定义 访问者模式是一种行为型设计模式,它允许我们向一个类的对象添加新的操作,而不改变该类的定义。访问者模式将操作的定义与对象结构分离,使得操作可以独立地扩展。 适用场景 对…

Orgill EDI需求分析

Orgill 是一家位于美国的家族企业,主要为五金零售商、建材供应商及相关行业提供全面的分销服务和支持,覆盖范围遍及全球。 EDI需求分析 EDI全称Electronic Data Interchange,中文名称是电子数据交换,也被称为“无纸化贸易”。EDI…

Oracle Agile PLM Web Service Java示例测试开发(一)环境环境、准备说明

1 说明 1.1 PLM信息介绍 PLM:Oracle的产品Agile PLM(Agile Product Lifecycle Management) 版本号:9.3.6 (Build 47) Path:https://IP:7002/Agile/default/login-cms.jsp 1.2 开发工具和环境说明 开发工具&#xf…

Android vendor.img中文件执行权问题

问题 Android 9、11往vendor.img增加文件,烧写到设备后发现增加的可执行文件没有执行权限。经过漫长查找,终于找到了问题的根源,谨以此篇献给哪些脚踏实地的人们。 根本原因 system/core/libcutils/fs_config.cpp文件,fs_confi…

27.日常算法

1. 最后一个单词的长度 题目来源 给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 示例 1: 输入:s “Hello Wor…

为AI聊天工具添加一个知识系统 之74 详细设计之15 正则表达式 之2

本文要点 要点 本项目&#xff08;为AI聊天工具添加一个知识系统&#xff09;中的正则表达式。 正则表达式的三“比”。正则表达式被 一、排比为三种符号&#xff08;元符号-圈号&#xff0c;特殊符号-引号&#xff0c;普通符号-括号&#xff09; 引号<<a线性回归bo…

设计模式的艺术-代理模式

结构性模式的名称、定义、学习难度和使用频率如下表所示&#xff1a; 1.如何理解代理模式 代理模式&#xff08;Proxy Pattern&#xff09;&#xff1a;给某一个对象提供一个代理&#xff0c;并由代理对象控制对原对象的引用。代理模式是一种对象结构型模式。 代理模式类型较多…

谷云科技陆才慧:数据集成,被忽视的数字化转型“幕后英雄”

大数据产业创新服务媒体 ——聚焦数据 改变商业 科技飞速发展&#xff0c;大数据浪潮席卷全球&#xff0c;数字化脚步日趋加快&#xff0c;然而数据集成在大众的认知中却似乎没有很大的变化。那么事实果真如此吗&#xff1f;答案是否定的。即使在AI功能日趋完善的当下&#xf…