Java和Android程序员都应该掌握的虚拟机知识

Java和Android程序员都应该掌握的虚拟机知识

/   今日科技快讯   /

近日,中国互联网络信息中心(CNNIC)发布的第45次《中国互联网络发展状况统计报告》显示,截至2020年3月,我国网民规模达9.04亿,较2018年底增长7508万,互联网普及率达64.5%,较2018年底提升4.9个百分点。手机网民规模达8.97亿,较2018年底增长7992万,我国网民使用手机上网的比例达99.3%,较2018年底提升0.7个百分点。

/   作者简介   /

本篇文章来自Pingred_hjh的投稿,分享了一篇简单好懂的Java虚拟机知识入门指南,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。

Pingred_hjh的博客地址:

https://me.csdn.net/qq_39867049

/   正文   /

Java虚拟机,如果要详细讲,可以写成一本书,但今天我的重点是想总结虚拟机的一些基础的知识点,让大家对虚拟机的内存空间有一个深刻的认识。

首先,这里要说一下一个基本流程,当你的Java代码写好了之后,是保存在XX.java文件中,然后因为要让计算机识别你写好的代码,所以要将文件编译成XXX.class文件,最后,就是运行这个字节码文件从而执行你写的代码,而编译和运行的工作都是虚拟机干的。

Java和Android程序员都应该掌握的虚拟机知识

正如上图所示那样,编译的时候还是在硬盘中执行的,而运行则是在你计算机的内存中执行的,你可以理解虚拟机把这个字节码文件拿到内存中运行,而虚拟机此时会在内存中划分一块空间块,这个空间块就是拿来运行字节码文件里的代码。

而我们就是要研究这个由虚拟机划分的内存空间里的东西。

现在依然还有很多人觉得该内存空间里只有堆内存和栈内存,相信对于很多Java工程师来讲这两块区域应该很熟悉。实际上,严格来讲,虚拟机中的内存是划分为若干个不同的数据区域,主要5个:堆、方法区、虚拟机栈、本地方法栈和程序计数器。如下图所示:

Java和Android程序员都应该掌握的虚拟机知识

 

而平常我们说的栈内存就是虚拟机栈,虚拟机会在虚拟机栈中会创建一个栈帧,栈帧除了用来调用方法并执行方法的,它里面还有局部变量表,操作数栈,动态连接和返回地址。

局部变量表存储每个变量值,也就是平时在方法内部定义的局部变量以及在调方法时传的参数,都是存储在局部变量表里。当虚拟机把java文件编译成字节码文件的时候,会对程序里的方法进行检查,然后确定每个方法需要分配的最大局部变量表的容量。

操作数栈,就是存储要进行操作的变量,是后入先出的结构栈,跟局部变量表一样也是在编译的时候就会确定好它的最大容量。当方法执行的时候,刚开始操作数栈是空的,然后随着执行的过程中会对操作数元素进行压栈和弹出。

返回地址,是确保方法在退出后返回到方法被调用的位置的地址信息。当一个方法在正常退出或异常退出完成后,虚拟机栈中的返回地址就会被拿来恢复它的上层方法执行状态。

可能说完这些概念之后还是有点抽象,以下举个例子你就明白了。这里写段代码: 

Java和Android程序员都应该掌握的虚拟机知识

                                             

  以上这个方法在内存中执行的过程是这样的:

  1. 假设该方法是写在Sum.java文件里,虚拟机对它进行编译时会去确定好栈帧中局

    部变量表和操作数栈的容量,然后在创建局部变量表和操作数栈的时候根据这个

    容量来创建便可。

  2. 然后执行int x = 1的时候其实就是先将常量1压入操作数栈栈顶,然后再把它弹出栈并且放入到局部变量表索引为1的位置里,作为变量x的值。

  3. 接着int y = 2时也一样,将常量2压入操作数栈顶,然后再弹出来并且放入到局部变量表索引为2的位置里,作为y变量的值。

  4. 接着执行int z = x + y时,先将此时局部变量表里的值1和值2压入到操作数栈中,此时栈顶是2,底下是1,然后进行加法操作得到值3,然后此时栈顶就是该结果值3,将该值3出栈,存入到局部变量表索引为3的位置。

  5. 最后执行return z的时候,将局部变量表中的3压入回操作数栈栈顶,然后将操作数栈栈中的3返回给上层方法。到这里整个sum方法执行完毕,而布局变量表和操作数栈也会跟着销毁。

以上过程如果要画成图可以这样表示:

Java和Android程序员都应该掌握的虚拟机知识

整个流程图虽然很长,但结构非常容易理解,要操作的元素都出入操作数栈,而变量值则存按索引位置存到局部变量表里,请结合上文五点步骤描述来理解此图。

最后也可以使用javap 命令来查看该类的字节码指令,验证是否像上图描述的流程一样执行该方法。这点读者可自行去确认,这里就不作讲解了。

堆内存这块区域则是存放对象实例的,大家应该不陌生了,当堆内存中的对象没有被引用指向时,就变成了可回收对象,被GC进行垃圾回收。

方法区,主要存储类信息(类模板),常量和静态变量等。

程序计数器,用来记录当前线程执行的位置,也就是平时我们在编辑器里不是会看到一段代码的左侧会有数字记录每一行吗,这些行数就是线程用来记录当前方法执行到哪个位置,这样CPU在切换回线程时仍然能继续上一次位置继续执行。

Java和Android程序员都应该掌握的虚拟机知识

本地方法栈,和虚拟机栈基本一样,只是本地方法栈是针对native(本地)方法,当涉及到JNI会使用到本地方法栈。

相信看到这里,大家应该对虚拟机内存空间应该有一个较好的认识,这样在下次写代码的时候,可以自己作一个感性的底层想象:

Java和Android程序员都应该掌握的虚拟机知识

创建一个对象,并且创建一个变量来指向该对象,Object o = new Object()代码在内存空间里正如上图所示。

推荐阅读:

这本《第三行代码》,让大家久等了!

Android 11来了,快!扶我起来

Java的值传递和引用传递,你真的搞清楚了吗?

欢迎关注我的公众号

学习技术或投稿

Java和Android程序员都应该掌握的虚拟机知识

Java和Android程序员都应该掌握的虚拟机知识

长按上图,识别图中二维码即可关注