一:编程语言兼容底层系统的方式大概分为两种

1、通过编译器实现兼容

例如C、C++等编程语言,既能运行与Linux系统,也能运行与Windows系统;既能运行于x86平台,也能运行于AMD平台。这种能力并不是编程语言所具备的,而是由编译器所赋予的。针对不同的硬件平台和操作系统,开发特定的编译器,编译器能够将同一段C/C++语言翻译成与目标平台匹配的机器指令,从而实现语言的兼容性。

2、通过中间语言实现兼容

Java、C#等语言,都是属于这种兼容方式

Java/C#被编译后,生成中间语言(ML),中间语言指令由虚拟机负责解释和执行。虚拟机在运行期间将中间语言实时翻译成与特定底层平台匹配的机器指令并运行。无论程序最终运行在那种底层平台上,源代码被编译生成的中间语言指令都是相同的。中间语言的兼容性由虚拟机啊负责完成。

二:中间语言翻译

将中间语言翻译成对应的机器指令并得以执行。

1、从中间语言翻译到机器码

一种可行的办法是:使用C程序,将字节码的每一条指令,都逐行的解释成C程序。当执行字节码的程序——JVM程序本身被编译后,字节码指令所对应的C程序呗一起编译成机器码,于是虚拟机在解释字节码指令时,自然会执行对应的C程序对应的本地机器码。

但是这种方式效率太低。

2、直接翻译为机器码

利用CPU执行代码的原理。要让CPU执行一段代码,只需将CS:IP段寄存器执行到代码段入口即可。

CS寄存器保存段地址,IP保存偏移地址。CS和IP两个寄存器的值能够唯一确定内存中的一个地址,CPU在执行指令之前,便通过这两个寄存器定位到目标内存位置,并将该位置处的机器指令取出来进行运算。

例程:利用C程序提供的语法糖(语法规则),让CS:IP直接指向一串机器码

const unsigned char code[] = "\x55\x89\x35\x8b\x45\x0c\x8b\x55\x08\x01\xd0\x5d\xc3";
int main(){int  a = 5;int  b = 3;int (*fun)(int,int);//定义函数指针fun = (void*)code;//初始化函数指针,将其指向code机器码的入口int r = fun(a,b);printf(r);return 0;
}

本例实现两个正整数之和。fun指针指向一个char数组首地址。

3、本地编译

虽然将中间语言翻译为机器码并直接运行,其效率比使用C语言来解释执行,已经提高了很多,但是,由于中间语言有自己的一套内存管理和代码执行方式。因此,实现同样的功能,虽然使用中间语言只需写几行代码,但是翻译后的机器码,比直接编写机器码,还要多出很多指令。效率不高。

为提供性能,JVM提供了一种机制,能够将中间语言(字节码)直接翻译为本机器指令。

三:指令

通过编译器将Java语言翻译成中间语言,然后再交给虚拟机,其再将中间语言翻译成对应机器平台上的指令。

所谓的中间语言就是Java字节码指令集。

Java的所有的指令都是用8位二进制描述,因此Java的指令总数不超过255个。

1、常见的汇编指令

主要学习java虚拟机执行引擎的内部实现机制,学习简单的5个汇编指令。

(1)数据传送指令

这些指令主要在寄存器与内存、寄存器与输入/输出端口之间传送数据。例如

//将自然数1传送到eax寄存器

movl 1, %eax

//将站定数据弹出至eax寄存器

pop %eax

(2)算术运算指令

包括基本的四则运算、浮点运算、数学运算(正弦等)

//将自然数3与eax寄存器中的数累加,并将结果存进eax中

add 3 ,%eax

// 对ebx寄存器中的数加增1

inc %ebx

(3)逻辑运算符

与、或、非、左移、右移等指令

//将eax寄存器中的数左移1个二进位

shl %eax,1

//对al寄存器中的数和操作数进行与操作

and al ,00111011B

(4)串指令

连续空间分配,连续空间取值,传送等。

(5)程序转移指令

if else判断、for循环、while循环、函数调用等

常见的:jmp跳转、loop循环、ret等

四:JVM指令

Java是面向对象的编程语言,自然要有一套支持类型操作的特殊指令。

1、数据交换指令

对JVM内存而言,分为操作数栈、局部变量表、java堆、常量池、方法区。数据交换指令就是支持数据在这些内存区域之间传送和交换。JVM执行逻辑运算的主要地方是操作数栈(iinc指令除外,该指令可以直接对局部变量进行运算)。无论你把数据放在堆栈中,还是放在常量池,只要执行运算,最终JVM都会将数据传送到操作数栈中。而硬件执行运算的区域是寄存器,无论你把数据放在数据段中,还是代码段,最终CPU都会讲数据传送到寄存器中。逻辑运算完成后,再把结果转义出去。

JVM规范还提供了像getfeild和putfeild这样的指令:实现java堆中的对象的字段和操作数栈之间的数据交换;

getstatic和putstatic这样的指令:实现类中的字段和操作数栈之间的数据交换;

baload、bastore、caload和castore这样的指令:实现JVM堆中的数组和操作数栈之间的数据交换

2、函数调用指令

由于Java中的函数类型比较丰富,因此必然要支持更多的函数调用方式。例如:invokevitual、invokeinterface、invokespecial、invokestatic和return等。这比硬件所支持的函数调用指令集要丰富一些。x86主要使用call和ret来保存现场和恢复现场,往往会伴随CPU物理寄存器入栈和出栈。

JVM没有物理寄存器,所以用操作数栈和PC寄存器来替代。JVM保存现场和恢复现场的解决方案是向Java堆栈中压入一个栈帧,函数返回时从java堆栈中弹出一个栈帧。

JVM调用函数时候,不能像CPU硬件那样,直接跳转就能找到对应代码段。这是因为Java函数的代码并没有被存放在代码段中,而是放在了一个code缓存中。每一个Java函数代码块在这个code缓存中都会有一个索引位置,最终JVM会跳转到这个索引位置处执行Java函数调用。同时,Java的函数一定是被封装到类中的,因此JVM在执行函数调用时,还需要经过寻址等等一些列运算,最终才能定位这个入口。

3、运算指令集

JVM和运算相关的指令集主要有算术运算,位运算,比较运算,逻辑运算等。

常见运算指令: iadd:对两个int型数据求和      isub:对两个int型整数做减法    fadd:对两个float浮点数进行求和    ddiv:两个double双精度型数据相除等

4、控制转移指令

与CPU硬件一样,JVM也提供了常见的控制转移指令。

5、对象创建一类型转换指令

JVM提供一套创建对象的指令。在Java语法层面使用关键字new可以实例化一个对象,而对应的字节码也是new。

JVM规范还提供了“窄化类型转换”指令与“宽化类型转化”指令。后者JVM内部天生支持。

除了上述指令外,JVM规范还提供很多其他物理CPU没有的指令。例如,抛出异常指令,用于线程同步的指令等。

总结:

Java语言所要解决的是如何能够不关注底层技术细节就能实现兼容性,通过中间语言来实现跨平台兼容的目标。由于中间语言并不是本地机器指令,机器无法直接识别,因此中间语言并不能直接由物理CPU运行。使用虚拟机来解释中间语言,将中间语言翻译成与之对应的本地机器语言。

高效的方式是直接将Java字节码指令翻译成本地机器指令,运行期直接由Java虚拟机调用对应的机器指令来执行,这种调用机制主要依靠CPU所提供的call和jmp指令。

ps:

该学习笔记基于学习封亚飞作者的《揭秘Java虚拟机—JVM的设计原理与实现》。第一次写博客并发布,基本上都是学习笔记,如有侵犯版权请联系我删除。喜欢就点赞吧。

Java虚拟机学习笔记(一)—Java虚拟机概述相关推荐

  1. Java SE 学习笔记5 Java阶段复习

    计算机.Java基础 一.计算机 1.硬件介绍 2.中央处理器 3.比特(bit)和字节(byte) 4.内存 5.存储设备 6.输入和输出设备 二.Java介绍 1.常用的dos命令 2.java语 ...

  2. Java基础学习笔记三 Java基础语法

    Scanner类 Scanner类属于引用数据类型,先了解下引用数据类型. 引用数据类型的使用 与定义基本数据类型变量不同,引用数据类型的变量定义及赋值有一个相对固定的步骤或格式. 数据类型 变量名 ...

  3. 【java项目学习笔记】Java学生管理系统(纯后端基础--增删改查)

    学生管理系统 在一所学校中,对学生人员流动的管理是很麻烦的,本案例要求编写一个学生管理系统,实现对学生信息的添加.删除.修改和查询功能.每个功能的具体要求如下: 系统的首页 用于显示系统所有的操作,并 ...

  4. java notifier_Java学习笔记---4.Java的分支循环语句

    这一部分同样比较熟悉了,但switch语句的使用还需要注意一下. public class Chose { public static void main(String args[]) { int g ...

  5. java中哪些可以私有化_《Java基础学习笔记》JAVA修饰符之私有化(Private)

    1,什么是private修饰符? private是权限修饰符,用于修饰类中的成员(成员变量,成员函数). private修饰后的成员只在本类中有效. /* 例: * 将age私有化以后,类以外即使建立 ...

  6. 《Java基础学习笔记》JAVA面向对象之封装

    1,封装,是指隐藏对象的属性和实现细节,仅对外提供公共访问方式. 2,好外:        a)将变化隔离.        b)便于使用.        c)提高重用性.        d)提高安全性 ...

  7. Java NIO 学习笔记(三)----Selector

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  8. Java NIO 学习笔记(五)----路径、文件和管道 Path/Files/Pipe

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  9. Java 虚拟机学习笔记 | 类加载过程和对象的创建流程

    前言 创建对象是 Java 语言绕不开的话题,那么对象是如何创建出来的呢?我们今天就来聊一聊.对象创建第一步就是检查类是否加载,而类的加载又牵扯到类的加载过程.如果单说对象的创建而绕开类的加载过程,感 ...

  10. 学习笔记【Java 虚拟机②】垃圾回收

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 总目录 学习笔记[Java 虚拟机①]内存结构 学习笔记[Java 虚拟机②]垃圾回收 学习笔记[Java ...

最新文章

  1. 使用wide和buildbox构建完全在线的开发集成环境
  2. 【Hadoop】MAC下hadoop2.6安装以及执行wordcount
  3. AntDesign Form表单字段校验的三种方式
  4. Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】...
  5. 快速上手Tomcat(eclipse中配置tomcat)
  6. 走进markdown
  7. 如何使用矩池云的保存环境功能
  8. SpringMVC拦截器-路径语法-略坑
  9. nodejs基础整理
  10. Windows Phone 7 不温不火学习之《Expression Blend 创建渐变效果和创建Storyboard动画》...
  11. Monent.js:强大的日期处理类库
  12. 点击控件动态创建新页面
  13. Docker从理论到实践(五)------Dokcer容器
  14. 回顾线性系统和非线性系统
  15. windows破解锁屏密码(亲测有效:再也不怕别人锁屏防你啦!)
  16. TIM-VX编译体验
  17. kitti点云地图拼接
  18. c语言关于数组排序法和插入一个数的详细讲解
  19. 天猫服饰新推“良品臻选”,请了一群挑剔的女人给服装“挑刺”
  20. 绍兴印象二 从三味书屋到百草园

热门文章

  1. 【RPA】UIpath Academy BA篇
  2. LeetCode 221. 最大正方形
  3. oracle网页客户端工具
  4. qtCreator安装windows sdk cdb
  5. torch.zeros_like() 和 torch.zeros()的区别
  6. 帝国CMS教程:ECMS(帝国CMS)搜索伪静态
  7. 计算机怎么删除我的苹果设备管理器,怎么删除电脑我的苹果设备管理器
  8. Web安全 -- 信息收集(上)
  9. 用Python爬取王者农药英雄皮肤 原
  10. Myeclipse中安装mybatis generator插件有两种方式,一种是在线安装,一种是离线安装。