Java 执行过程中的内存模型
一、前言
本文的主要工作:尝试以时间顺序追踪一遍 Java 执行的整个过程,以及展示 JVM 中内存模型的相应变化。
本文的主要目的:希望能够通过 Java 执行过程的冰山一角,增进对编程语言工作原理的理解。
以下面这段代码为例,追踪它的执行过程:
public class Car {
private int speed;
public void setSpeed(int speed) {
this.speed = speed;
}
public void getSpeed() {
System.out.println(speed);
}
public static void main(String[] args) {
Car car = new Car();
car.setSpeed(3);
car.getSpeed();
}
}
二、执行过程
接下来是具体的执行过程,总共包含五个步骤:编译、加载、执行 main 方法、执行成员方法、方法返回。
Step1:编译
首先,在我们完成上述这段源码之后,要想让程序跑起来,我们需要将其编译成为字节码文件。字节码是一种跨平台的JVM机器语言,它能够被JVM所解析,而无关底层的操作系统。
Step2:加载
当代码需要被调用时,JVM 会加载目标字节码至方法区,并转化为方法区的运行时数据结构,这里的加载过程是通过类加载器完成的。然后内存中(不一定是堆)会生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据结构的访问入口。

Step3:执行 main 方法
main 方法可以通过 java.lang.Class 对象进行调用,参考如下代码:
Method method = targetClass.getDeclareMethod("main", String[].class);
method.invoke(null, (Object) new String[0]);
之后 PC 寄存器将会指向方法区中的 main 函数地址,线程栈中会生成对应的栈桢,其主要用于存放当前方法的局部变量表、操作栈、以及方法返回地址。接下来,PC 寄存器向后地址偏移,执行引擎开始执行 main 方法体。当语句 Car car = new Car() 执行完毕,栈桢与堆中的相应变化如下:

Step4:执行成员方法
对象 car 的 setSpeed 方法调用过程和 main 类似,通过索引 car 的成员方法地址,PC寄存器将指向方法区中的 setSpeed 函数地址,同时线程栈中将产生新的栈桢,其中的方法返回地址用于保存原有 PC 地址偏移。当赋值语句 this.speed = speed 执行完毕,栈桢与堆中发生的相应变化如下:

Step5:方法返回
随着 setSpeed 方法的执行结束,Stack 中的相应栈桢出栈,栈顶指针重新指向 main 栈桢。同时 PC 寄存器将根据方法返回地址进行还原,从而继续执行 main 的方法体。当 main 方法也执行完毕出栈后,主线程与虚拟机实例销亡,程序结束。
三、杂谈
虚拟机或某一门程序语言,作为一种底层实现,可以满足上层用户的绝大部分需求,但是需求是与时俱进的,总有一天用户需要编写自己的底层实现,比如组件、框架、一门新语言。这时需要打开原有的规范,先破坏它,再重建它,从而定义自己的规范。这也许是我们需要探究底层的缘由之一吧。
参考链接
[1] <<深入理解Java虚拟机>>
[2] https://www.cnblogs.com/zzzz76/p/9282981.html
[3] https://www.cnblogs.com/zzzz76/p/8150862.html
[4] https://www.cnblogs.com/zzzz76/p/8076536.html
Java 执行过程中的内存模型的更多相关文章
- java中的内存模型
概述 Java平台自动集成了线程以及多处理器技术,这种集成程度比Java以前诞生的计算机语言要厉害很多,该语言针对多种异构平台的平台独立性而使用的多线程技术支持也是具有开拓性的一面,有时候在开发Jav ...
- Java实例化对象过程中的内存分配
Java实例化对象过程中的内存分配: https://blog.csdn.net/qq_36934826/article/details/82685791 问题引入这里先定义一个很不标准的“书”类,这 ...
- java中子类实例化过程中的内存分配
知识点: 子类继承父类之后,实例化子类时,内存中子类是如何分配内存的呢? 下面,自己会结合一个例子,解释一下,一个子类实例化过程中,内存是如何分配的 参考博客:http://www.cnblogs.c ...
- 深入理解java虚拟机(6)---内存模型与线程 & Volatile
其实关于线程的使用,之前已经写过博客讲解过这部分的内容: http://www.cnblogs.com/deman/category/621531.html JVM里面关于多线程的部分,主要是多线程是 ...
- (转载)JVM中的内存模型与垃圾回收
转载自微信公众号:Java高级架构(Java-jiagou)-----看完这篇文章,我奶奶都知道JVM中的内存模型与垃圾回收了! 六.内存模型 6.1 内存模型与运行时数据区 Java虚拟机在执行J ...
- Java虚拟机解析篇之---内存模型
今天闲来无事来,看一下Java中的内存模型和垃圾回收机制的原理.关于这个方面的知识,网上已经有非常多现成的资料能够供我们參考,可是知识还是比較杂的,在这部分知识点中有一本书不得不推荐:<深入理解 ...
- 详解JVM中的内存模型是什么?
强烈推荐 不管是找工作还是提升水平,都建议读一下<深入理解Java虚拟机>这本书,详细讲解了JVM中的内存管理.类加载过程.垃圾回收以及最重要的性能调优实战. 本博客也是参考了这本书,有不 ...
- 转:Oracle中SQL语句执行过程中
Oracle中SQL语句执行过程中,Oracle内部解析原理如下: 1.当一用户第一次提交一个SQL表达式时,Oracle会将这SQL进行Hard parse,这过程有点像程序编译,检查语法.表名.字 ...
- SQL SERVER 2008:内部查询处理器错误: 查询处理器在执行过程中遇到意外错误
今天一个同事突然告诉我,以前跑得很正常的一个SQL语句,执行时突然报如下错误: 消息1222,级别16,状态18,第1 行 已超过了锁请求超时时段. ...
随机推荐
- Idea利用maven创建web项目,并配置tomcat
参考http://blog.csdn.net/myarrow/article/details/50824793#comments
- win shift s截图不能用(已解决)
win10上面 win shift s不能的原因是快捷键冲突导致的: 比如说你的电脑上安装了OneNode2016(讽刺的是这是微软自家的软件),或者其他截图软件都有可能导致快捷键冲突,从而不能使用. ...
- chrome实现网页高清截屏(F12、shift+ctrl+p、capture)
打开需要载屏的网页,在键盘上按下F12,出现以下界面 上图圈出的部分有可能会出现在浏览器下方,这并没有关系.此时按下 Ctrl + Shift + P(Mac 为 ⌘Command +⇧Shift + ...
- Ubuntu20.04编译ffmpeg
1.安装编译所需工具,GCC 2.安装yasm nasm yasm和nasm是两个编译器,编译ffmpeg需要用到 安装命令: sudo aptitude install yasm nasm 3.安装 ...
- Mybatis-plus的使用步骤
Mybatis-plus的简单使用步骤 花开堪折直需折,莫待无花空折枝 导入依赖 <dependency> <groupId>org.projectlombok</gro ...
- 在md里画流程图
可以使用名为mermaid的代码块,即 ```mermaid``` 需要md解析器能解析mermaid mermaid使用详情参见
- Mac上最好用的软件集合,没有之一
前言 题主从 windows 系统换成 macOS 系统已经4年多了.对于没有用过 Mac 电脑的人来说,可能无法理解 Mac 好用在哪里.不过对于一个用过 Mac 的开发者来说,从 windows ...
- MySql中的有条件插入 insert where
假设现在我们有这样的需求:当数据库中不存在满足条件的记录时,可以插入一条记录,否则程序退出.该怎么实现? 1年以上工作经验的人应该都能立即想到:去检查一下库里有没有记录,没有就插入,有就结束. int ...
- Serverless 如何应对 K8s 在离线场景下的资源供给诉求
本文整理自腾讯云云原生产品团队的专家产品经理韩沛在 Techo 开发者大会云原生专题的分享内容--Kubernetes 混部与弹性容器.本次分享主要分为三部分:基于 K8s 的应用混部.提升应用混部效 ...
- N叉树的最大深度-DFS
再看这道题之前,先来一道类似的简单题. 题目:求二叉树的最大深度 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示 ...