前言
《深入理解Java虚拟机》确实是一本神书,但却不太适合入门,太过专业,细节很多,读者很容易就陷入到细节中去,结果看完后,感觉懂了一些,却有感觉串不起来,因此,笔者试着用一张图和13行代码来串下。
由于能力有限文中有很多地方都很不严谨,甚至描述错误,还请谅解
阅读建议:看不懂或者有疑问的地方,先不用管,先看完,有个整体把握,然后有问题的再去查资料
废话少说,先放出题目中的 一图13行代码
(哈哈,有点标题党了,这么一张图,不过不要被图吓到,下文会慢慢来拆解)
public class Demo { public static void main(String[] args) { //这里搞个对象,就是为了引出对象创建过程 Are are = new Are(); are.f(); } } public class Are { public int f(){ int a=33,b=44; return 33+44; } }
零、JVM概览
先来张图JVM的整体结构图,来打个印象!
(下面这段话,看不太懂没关系,等全文看完,再回过头来看试试)
0、首先,是上面的代码,经过编译后,生成两个Demo.class,Are.class文件后,运行 java Demo.java 命令后,程序正式开始运行!
(这里就涉及到编译和class文件了,对应《深入理解Java虚拟机 第2版》的第6章和第四大部分, 后文统称《深入》)
1、首先,JVM 的类加载器从磁盘上加载Demo.class 类文件到内存中来,将类可执行的代码存放在的方法区中。
(你看,这里就是涉及到什么是class文件、类加载过程以及运行时数据区,对应《深入 2.2.5、6、7.3 》)
2、加载完成后,JVM 创建一个主线程执行这个类文件的 main 方法,main 方法的输入参数和方法内定义的变量被压入主线程对应的一个栈。
(这里说线程对应的栈,就是Java虚拟机栈;而压入的过程其实也是执行引擎执行指令的过程,对应《深入》的第2.2、8.3)
3、如果在方法内创建了一个对象实例,这个对象实例信息将会被存放到堆里,而对象实例的引用,也就是对象实例在堆中的地址信息则会被记录在栈里。
(这里就涉及到对象的创建时机(《深入7.2》)、创建过程、以及对象的引用访问过程 (深入 2.3》)
4、程序计数器一开始存放的是 main 方法的第一行代码位置,JVM 的执行引擎根据这个位置去方法区的对应位置加载这行代码指令,将其解释为自身所在平台的 CPU 指令后交给 CPU 执行。
(到这里,程序计数器就出来,同时,"解释"的概念也出来了。对应《深入 2.2.1》《深入 8.4》)
5、如果在 main 方法里调用了其他方法,那么在进入其他方法的时候,会在 Java 栈中为这个方法创建一个新的栈帧,当线程在这个方法内执行的时候,方法内的局部变量都存放在这个栈帧里。当这个方法执行完毕退出的时候,就把这个栈帧从 Java 栈中出栈,这样当前栈帧,也就是堆栈的栈顶就又回到了 main 方法的栈帧,使用这个栈帧里的变量,继续执行 main 方法。
(方法调用、当前栈桢的概念也就出来了,对应《深入 8.2》《深入 8.3》)
6、在整个程序执行过程中,JVM创建一些后台线程进行内存的自动分配和回收
(在这里,就出现最重要的垃圾回收了,对应《深入 第3章》)
下面,开始拆解图啦!
一、编译
关于编译,简单理解就是把 开头的.java文件格式的代码,编译成类文件(.class文件)
(看到这里,可以跳到文章的第二章了)