Java虚拟机,如果要详细讲,可以写成一本书,但今天我的重点是想总结虚拟机的一些基础的知识点,让大家对虚拟机的内存空间有一个深刻的认识。
首先,这里要说一下一个基本流程,当你的Java代码写好了之后,是保存在XX.java文件中,然后因为要让计算机识别你写好的代码,所以要将文件编译成XXX.class文件,最后,就是运行这个字节码文件从而执行你写的代码,而编译和运行的工作都是虚拟机干的。
正如上图所示那样,编译的时候还是在硬盘中执行的,而运行则是在你计算机的内存中执行的,你可以理解虚拟机把这个字节码文件拿到内存中运行,而虚拟机此时会在内存中划分一块空间块,这个空间块就是拿来运行字节码文件里的代码。
而我们就是要研究这个由虚拟机划分的内存空间里的东西。
现在依然还有很多人觉得该内存空间里只有堆内存和栈内存,相信对于很多Java工程师来讲这两块区域应该很熟悉。实际上,严格来讲,虚拟机中的内存是划分为若干个不同的数据区域,主要5个:堆、方法区、虚拟机栈、本地方法栈和程序计数器。如下图所示:
而平常我们说的栈内存就是虚拟机栈,虚拟机会在虚拟机栈中会创建一个栈帧,栈帧除了用来调用方法并执行方法的,它里面还有局部变量表,操作数栈,动态连接和返回地址。
局部变量表存储每个变量值,也就是平时在方法内部定义的局部变量以及在调方法时传的参数,都是存储在局部变量表里。当虚拟机把java文件编译成字节码文件的时候,会对程序里的方法进行检查,然后确定每个方法需要分配的最大局部变量表的容量。
操作数栈,就是存储要进行操作的变量,是后入先出的结构栈,跟局部变量表一样也是在编译的时候就会确定好它的最大容量。当方法执行的时候,刚开始操作数栈是空的,然后随着执行的过程中会对操作数元素进行压栈和弹出。
返回地址,是确保方法在退出后返回到方法被调用的位置的地址信息。当一个方法在正常退出或异常退出完成后,虚拟机栈中的返回地址就会被拿来恢复它的上层方法执行状态。
可能说完这些概念之后还是有点抽象,以下举个例子你就明白了。这里写段代码:
以上这个方法在内存中执行的过程是这样的:
-
假设该方法是写在Sum.java文件里,虚拟机对它进行编译时会去确定好栈帧中局部变量表和操作数栈的容量,然后在创建局部变量表和操作数栈的时候根据这个容量来创建便可。
-
然后执行int x = 1的时候其实就是先将常量1压入操作数栈栈顶,然后再把它弹出栈并且放入到局部变量表索引为1的位置里,作为变量x的值。
-
接着int y = 2时也一样,将常量2压入操作数栈顶,然后再弹出来并且放入到局部变量表索引为2的位置里,作为y变量的值。
-
接着执行int z = x + y时,先将此时局部变量表里的值1和值2压入到操作数栈中,此时栈顶是2,底下是1,然后进行加法操作得到值3,然后此时栈顶就是该结果值3,将该值3出栈,存入到局部变量表索引为3的位置。
-
最后执行return z的时候,将局部变量表中的3压入回操作数栈栈顶,然后将操作数栈栈中的3返回给上层方法。到这里整个sum方法执行完毕,而布局变量表和操作数栈也会跟着销毁。
以上过程如果要画成图可以这样表示:
整个流程图虽然很长,但结构非常容易理解,要操作的元素都出入操作数栈,而变量值则存按索引位置存到局部变量表里,请结合上文五点步骤描述来理解此图。
最后也可以使用javap 命令来查看该类的字节码指令,验证是否像上图描述的流程一样执行该方法。这点读者可自行去确认,这里就不作讲解了。
堆内存这块区域则是存放对象实例的,大家应该不陌生了,当堆内存中的对象没有被引用指向时,就变成了可回收对象,被GC进行垃圾回收。
方法区,主要存储类信息(类模板),常量和静态变量等。
程序计数器,用来记录当前线程执行的位置,也就是平时我们在编辑器里不是会看到一段代码的左侧会有数字记录每一行吗,这些行数就是线程用来记录当前方法执行到哪个位置,这样CPU在切换回线程时仍然能继续上一次位置继续执行。
本地方法栈,和虚拟机栈基本一样,只是本地方法栈是针对native(本地)方法,当涉及到JNI会使用到本地方法栈。
相信看到这里,大家应该对虚拟机内存空间应该有一个较好的认识,这样在下次写代码的时候,可以自己作一个感性的底层想象:
创建一个对象,并且创建一个变量来指向该对象,Object o = new Object()代码在内存空间里正如上图所示。
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
上述【高清技术脑图】以及【配套的架构技术PDF】可以 关注我 【主页简介】 或者【简信】免费获取
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
网友评论