【歪讲拉勾】1 JVM内存结构
< 返回列表时间: 2020-07-28来源:OSCHINA
文章内容输出来源:拉勾教育Java高薪训练营
前言
对于面试中涉及的一些问题,大多是层次多,知识点杂,不方便记忆,经常是一听就会,一面就忘。 我想到了一个对自己很有效的记忆方法:类比联想记忆法。
其实这个方法大家很熟悉,也很常用,只是需要找到比较贴切且适合自己的事物进行关联。 特此分享一下自己的经验。本文目的不在于知识的讲解,而在于知识的持久化。如有错误,欢迎指正。
不知道大家之前对jvm的内存结构能记住多少,认真看完以后尝试天天回忆下这个场景。 因为除了第一次建立记忆连接以外,还需要经常在脑中反复强化这个连接,才能达到深刻记忆的效果。
先整体浏览下JVM内存结构:大体上分为三个层次,二十多个知识点。

第一层
概念
类加载器:作用是将java 文件经过编译后会得到 .class 文件加载到内存。 本地库接口:用native修饰的,不能和abstract共同使用的,不显示方法体但却是用非Java语言实现方法体的方法。 运行时数据区:java虚拟机在执行Java程序的过程中会把它管理的内存分为若干个不同的数据区域。 执行引擎:jvm核心组成部分之一,建立在处理器、硬件和操作系统层面之上。引擎在执行代码时会有解释执行和编译执行两种选择,输入字节码文件,解析字节码输出结果。
类比
回顾完基本概念后,我们再关联上一个更加容易记忆的场景,左侧为类比事物,右侧为对应知识点。
想象一下一辆刚刚驶入加油站的汽车:
司机拿起加油枪(类加载器) 对准加油口(本地库接口)开始加油(开始类加载的过程,后边会再分析) 加油的目的是供给发动机可以使用的燃料(执行引擎) 然后才可以让让车继续保持行驶状态(运行时数据区)
第二层:类加载器
概念
加载:指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。 链接:当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中。类连接又可分为如下3个阶段。 验证:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致。 准备:负责为类的静态变量分配内存,并设置默认初始值。 解析:将类的二进制数据中的符号引用替换成直接引用。 初始化:为类的静态变量赋予正确的初始值。 使用:业务处理中被引用。 销毁:不再使用时被垃圾回收。
类比
再来类比下汽油使用的整个过程:
加载:将汽油添加到油箱。 链接:让发动机的油路中充满汽油。 验证:检查汽油是否符合发动机要求。 准备:汽油和发动机已完成启动前的准备状态。 解析:汽油开始燃烧并产出动力,化学燃料转换成物理的做功。 初始化:发动机启动完毕。 使用:汽车行驶过程中,发动机使用汽油持续运转。 销毁:汽油被消耗。
第二层:运行时数据区
概念
程序计数器:记录的是正在执行的虚拟机字节码指令的地址。 虚拟机栈:Java 方法执行的内存模型。 本地方法栈:区别于Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native 方法服务。 堆:这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。 方法区:属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
类比
程序计数器:记录汽车行驶距离的里程表。 虚拟机栈:电动车电池。 本地方法栈:汽油车油箱。 堆:可以堆放大件货物的后备箱。 方法区:可以提供操作汽车的各种方法的驾驶区域。
第三层:虚拟机栈
概念

栈帧( Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接 (Dynamic Linking)、 方法返回值和异常分派( Dispatch Exception)。栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。 局部变量表:一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。 操作数栈:一个后进先出栈,其最大深度在编译的时候已经确定了。当一个方法刚刚开始执行的时候,这个方法的操作数占是空的,在方法的执行过程中,会有各种字节码指令往操作数占中写入和提取内容,这就是出栈/入栈动作。 动态链接:每一个栈帧都包含一个执行运行时常量池中该栈帧所属方法的引用。持有这个引用是为了支持方法调用过程中的动态连接。 返回出口:方法正常退出,将会返回程序结束其的值给上层方法,经过调整之后以指向方法调用指令后面的一条指令,继续执行上层方法。 正常完成出口:方法正确执行,执行引擎遇到方法返回的指令,回到上层的方法调用者。 异常完成出口:方法执行过程中发生异常,并且没有处理异常,这样是不会给上层调用者产生任何返回值。
类比
每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。对应着每一次快递派送:
局部变量表:每次派送的货物清单。 操作数栈:货车的货箱,只能栈式搬运货物。 动态链接:实时动态规划路径。 返回出口:到达终点以后就可以返回了。
总结
最后,我们再回顾下整个思路,方便平时反复回忆。 货车进入加油站进行加油时需用加油枪(类加载器)对准了加油口(本地库接口)。加过油的车可以让发动机(执行引擎)运转起来,并保持行驶状态(运行时数据区)。 加油过程中,汽油从油枪进入了油箱(加载),并抵达了发动机(链接)。这个过程中车载电脑检查了汽油(验证),并使汽油和发动机都进入启动前的准备状态(准备)。然后汽油开始燃烧,转化为动力势能(解析),发动机启动完成后(初始化)开始使用汽油(使用),当汽油燃烧后就被消耗了(销毁)。 所以驾驶员坐在可以操作汽车的驾驶室(方法区)操纵货箱(堆)载满货物的货车时,会观察记录移动距离的里程表和油箱指示灯(程序计数器),判断什么时候需要再次加油。而油电混合的汽车也会借助油箱(本地方法栈)的汽油燃烧给电池充电(虚拟机栈)。 货车的目的是将货箱(操作数栈)的货物(局部变量)运送到目的地(返回出口),途中会借助导航地图实时调整路线(动态链接)。
热门排行