java开发C语言编译器: JVM的基本原理
2017-05-11 12:07
309 查看
更详细的讲解和代码调试演示过程,请参看视频
用java开发C语言编译器
如果你对机器学习感兴趣,请参看一下链接:
机器学习:神经网络导论
上一节,我们把C语言编译成了可以被java虚拟机加载执行的java汇编语言。这节,我们就jvm的基本机制进行深入了解,如果不理解java虚拟机的体系结构,那么我们不可能把C语言转换成能顺利在虚拟机上执行的字节码。
把握java虚拟机,必须把握一点,那就是java虚拟机的运行是以栈为基础的。理解了这点,对jvm的理解就掌握了一大半。java程序运行时,当某个函数被调用是,jvm会创建一个执行环境,这个环境叫stack frame, 这个环境有三个需要理解的要点,第一是,stack frame 含有一个执行堆栈,任何指令的执行,都会围绕这个堆栈来进行。第二是局部变量数组,函数的输入参数和局部变量就存储在这个数组中。第三个是指令指针PC,它指向下一条要执行的指令。
举个例子,假设java 代码中有一个函数:
上面代码编译后,jvm会产生的stack frame 如下:
stack:
local_array: a, b
PC-> 把变量a 从local_array 取出,然后压入堆栈
把变量b 从local_array 取出,然后压入堆栈
把堆栈顶部两个元素弹出后相加,把结果压入堆栈
把堆栈顶部的元素弹出后返回。
假设函数的调用方式为 f(1,2) 那么stack frame 形式如下:
stack:
local_array: 1, 2
PC-> 把变量a 从local_array 取出,然后压入堆栈
把变量b 从local_array 取出,然后压入堆栈
把堆栈顶部两个元素弹出后相加,把结果压入堆栈
把堆栈顶部的元素弹出后返回。
执行第一条语句后,stack frame 如下:
stack: 1
local_array: 2
把变量a 从local_array 取出,然后压入堆栈
PC-> 把变量b 从local_array 取出,然后压入堆栈
把堆栈顶部两个元素弹出后相加,把结果压入堆栈
把堆栈顶部的元素弹出后返回。
继续执行当前PC指针指向的语句后,情况如下:
stack: 2, 1
local_array:
把变量a 从local_array 取出,然后压入堆栈
把变量b 从local_array 取出,然后压入堆栈
PC-> 把堆栈顶部两个元素弹出后相加,把结果压入堆栈
把堆栈顶部的元素弹出后返回。
继续执行后情况如下:
stack: 3
local_array:
把变量a 从local_array 取出,然后压入堆栈
把变量b 从local_array 取出,然后压入堆栈
把堆栈顶部两个元素弹出后相加,把结果压入堆栈
PC-> 把堆栈顶部的元素弹出后返回。
依次类推。
你可以看到,java指令运行时,必须确保指令需要的参数全部放在栈上,指令执行后如果有结果,结果也同样会存在在堆栈上。
有了上面的基本理论,我们可以看看上一节程序生成的java汇编代码:
指令getstatic 的作用就是把out对象压入前面所说的堆栈中。ldc 的作用是把字符串压入到前面所说的堆栈中,这两句执行后,堆栈情况如下:
stack:
“Hello java virtual machine!”
out
invokevirtual 指令执行时,它会从堆栈顶部取出两个元素,接着从第二个元素,也就是out对象中,找到要调用的方法,也就是println, 然后把堆栈第一个元素作为参数,调用println方法,执行完毕后,如果有返回值,则把返回值给压入堆栈。
理解了指令的执行原理后,其他语句完全可以跟下面的代码对应起来:
由此语句.class public CSourceToJava对应的就是java代码中类的声明部分:
public class CSourceToJava, 指令.method public static main 对应的就是静态函数main 的声明:public static void main。
语句Ljava/io/PrintStream; 表示对象的类型,例如对象out 的类型是java.io.PrintStream。前面的L表示该对象是一个类,如果前面还有一个左中括号,那表示该对象是一个数组,例如[Ljava/lang/String; 表示的是String[].
更详实讲解请参看视频。
更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
用java开发C语言编译器
如果你对机器学习感兴趣,请参看一下链接:
机器学习:神经网络导论
上一节,我们把C语言编译成了可以被java虚拟机加载执行的java汇编语言。这节,我们就jvm的基本机制进行深入了解,如果不理解java虚拟机的体系结构,那么我们不可能把C语言转换成能顺利在虚拟机上执行的字节码。
把握java虚拟机,必须把握一点,那就是java虚拟机的运行是以栈为基础的。理解了这点,对jvm的理解就掌握了一大半。java程序运行时,当某个函数被调用是,jvm会创建一个执行环境,这个环境叫stack frame, 这个环境有三个需要理解的要点,第一是,stack frame 含有一个执行堆栈,任何指令的执行,都会围绕这个堆栈来进行。第二是局部变量数组,函数的输入参数和局部变量就存储在这个数组中。第三个是指令指针PC,它指向下一条要执行的指令。
举个例子,假设java 代码中有一个函数:
int f(int a, int b) { return a+b; }
上面代码编译后,jvm会产生的stack frame 如下:
stack:
local_array: a, b
PC-> 把变量a 从local_array 取出,然后压入堆栈
把变量b 从local_array 取出,然后压入堆栈
把堆栈顶部两个元素弹出后相加,把结果压入堆栈
把堆栈顶部的元素弹出后返回。
假设函数的调用方式为 f(1,2) 那么stack frame 形式如下:
stack:
local_array: 1, 2
PC-> 把变量a 从local_array 取出,然后压入堆栈
把变量b 从local_array 取出,然后压入堆栈
把堆栈顶部两个元素弹出后相加,把结果压入堆栈
把堆栈顶部的元素弹出后返回。
执行第一条语句后,stack frame 如下:
stack: 1
local_array: 2
把变量a 从local_array 取出,然后压入堆栈
PC-> 把变量b 从local_array 取出,然后压入堆栈
把堆栈顶部两个元素弹出后相加,把结果压入堆栈
把堆栈顶部的元素弹出后返回。
继续执行当前PC指针指向的语句后,情况如下:
stack: 2, 1
local_array:
把变量a 从local_array 取出,然后压入堆栈
把变量b 从local_array 取出,然后压入堆栈
PC-> 把堆栈顶部两个元素弹出后相加,把结果压入堆栈
把堆栈顶部的元素弹出后返回。
继续执行后情况如下:
stack: 3
local_array:
把变量a 从local_array 取出,然后压入堆栈
把变量b 从local_array 取出,然后压入堆栈
把堆栈顶部两个元素弹出后相加,把结果压入堆栈
PC-> 把堆栈顶部的元素弹出后返回。
依次类推。
你可以看到,java指令运行时,必须确保指令需要的参数全部放在栈上,指令执行后如果有结果,结果也同样会存在在堆栈上。
有了上面的基本理论,我们可以看看上一节程序生成的java汇编代码:
.class public CSourceToJava .super java/lang/Object .method public static main([Ljava/lang/String;)V getstatic java/lang/System/out Ljava/io/PrintStream; ldc "Hello java virtual machine!" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V return .end method .end class
指令getstatic 的作用就是把out对象压入前面所说的堆栈中。ldc 的作用是把字符串压入到前面所说的堆栈中,这两句执行后,堆栈情况如下:
stack:
“Hello java virtual machine!”
out
invokevirtual 指令执行时,它会从堆栈顶部取出两个元素,接着从第二个元素,也就是out对象中,找到要调用的方法,也就是println, 然后把堆栈第一个元素作为参数,调用println方法,执行完毕后,如果有返回值,则把返回值给压入堆栈。
理解了指令的执行原理后,其他语句完全可以跟下面的代码对应起来:
public class CSourceToJava { public static void main(String[] args) { System.out.println("Hello java virtual machine!"); } }
由此语句.class public CSourceToJava对应的就是java代码中类的声明部分:
public class CSourceToJava, 指令.method public static main 对应的就是静态函数main 的声明:public static void main。
语句Ljava/io/PrintStream; 表示对象的类型,例如对象out 的类型是java.io.PrintStream。前面的L表示该对象是一个类,如果前面还有一个左中括号,那表示该对象是一个数组,例如[Ljava/lang/String; 表示的是String[].
更详实讲解请参看视频。
更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
相关文章推荐
- java开发C语言编译器:JVM 的基本操作指令介绍及其程序运行原理
- java开发C语言编译器:把C实现的快速排序算法编译成jvm字节码
- java开发C语言编译器:jvm的return指令以及局部变量的操作
- Java性能调优_深入Java程序性能调优(并行开发、JVM调优)
- Java性能调优_深入Java程序性能调优(并行开发、JVM调优)
- java开发C语言编译器
- java开发C语言编译器:把C语言的数组操作转换成java字节码
- JAVA开发(4) -JVM 内存溢出问题的解决
- JAVA开发之 2-JRE与JDK及JVM的区别
- Java JVM 运行机制及基本原理
- java开发C语言编译器:消除冗余语句和把ifelse控制语句编译成字节码
- 开发能支持多种JVM的java程序应注意的事项
- Java后台开发(2)——JVM参数设置和分析
- JDK&JRE&JVM_跨平台特性_开发环境配置_dos命令_字符集JAVA001-006
- myEclipse开发内存溢出解决办法myEclipse调整jvm内存大小java.lang.OutOfMemoryError: PermGen space及其解决方法
- java开发C语言编译器:为C语言提供API调用
- Java开发工具jvm配置参数
- 223_尚学堂_高淇_java300集最全视频教程_JVM核心机制_线程上下文类加载器_web服务器类加载机制_OSGI技术模块开发原理介绍
- java开发编译器:自底向上语法解析的基本原理
- java开发-JVM监控调优