jvm原理和代码运行的过程

一次编译,到处运行

java一直宣传的口号是:一次编译,到处运行。那么它如何实现的呢?我们看下图:

javac编译
java解释
java解释
java原程序
java字节码
jvm虚拟机
windows机器码
linux机器码
windows执行
linux执行

java程序经过一次编译之后,将java代码编译为字节码也就是class文件,然后在不同的操作系统上依靠不同的java虚拟机进行解释,最后再转换为不同平台的机器码,最终得到执行。这样我们是不是可以推演,如果要在mac系统上运行,是不是只需要安装mac java虚拟机就行了。那么了解了这个基本原理后,我们来看一下,一段程序是如何执行的。

public class HelloWorld {
    public static void main(String[] args) {        
        System.out.print("Hello world"); 
    }
}

这段程序从编译到运行,所经历的过程如下:

class文件
加载jvm.cfg文件
根据jvm.cfg的配置
JNI为本地方法他可以直接与操作系统交互
java源代码
java字节码
加载配置
加载jvm.dll文件
初始化jvm
获取JNI接口
操作Class文件
找到main文件执行

jvm基本结构

可能通过上面的描述,大家对JVM运行流程有了一个粗略的认识,那么JVM内部到底是怎么执行一个class文件的呢?

运行时常量池
对象存储
局部变量表_栈帧_操作数
线程结束自动释放
本地方法库_C语言
JNI直接操作
Class文件
类加载器
内存空间
方法区
垃圾回收GC
java堆
java栈
线程私有
本地方法栈
堆外内存

jvm内存分类介绍

JVM内存空间包含:方法区、java堆、java栈、本地方法栈。

  1. 方法区是各个线程共享的区域,存放类信息、常量、静态变量。

  2. java堆也是线程共享的区域,我们的类的实例就放在这个区域,可以想象你的一个系统会产生很多实例,因此java堆的空间也是最大的。如果java堆空间不足了,程序会抛出OutOfMemoryError异常。

  3. java栈是每个线程私有的区域,它的生命周期与线程相同,一个线程对应一个java栈,每执行一个方法就会往栈中压入一个元素,这个元素叫“栈帧”,而栈帧中包括了方法中的局部变量、用于存放中间状态值的操作栈,如果java栈空间不足了,程序会抛出StackOverflowError异常.

每个帧代表一个方法,Java方法有两种返回方式,return和抛出异常,两种方式都会导致该方法对应的帧出栈和释放内存。

  1. 本地方法栈角色和java栈类似,只不过它是用来表示执行本地方法的,本地方法栈存放的方法调用本地方法接口,最终调用本地方法库,实现与操作系统、硬件交互的目的。

  2. PC寄存器(程序计数器),说到这里我们的类已经加载了,实例对象、方法、静态变量都去了自己改去的地方,那么问题来了,程序该怎么执行,哪个方法先执行,哪个方法后执行,这些指令执行的顺序就是PC寄存器在管,它的作用就是控制程序指令的执行顺序。

执行引擎当然就是根据PC寄存器调配的指令顺序,依次执行程序指令。

  • 静态变量+常量+类信息+运行时常量池存在方法区中,实例变量存在堆内存中。
  • 基本类型的变量和对象的引用变量都是在函数的栈内存中分
posted @   张占岭  阅读(1356)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2018-08-20 我的那些年(8)~去朋友公司做网站开发
2018-08-20 我的那些年(7)~第一份互联网工作
点击右上角即可分享
微信分享提示