JVM : JAVA VIRTUAL MACHINE ,是一种虚构出来的机器。是虚拟的CPU,其中的很多组建都是模拟了CPU的功能。
运行时数据区及其主要功能
分布介绍一下不同区域的主要功能。
-
PC: Program Counter 程序计数器。存放指令的位置。在虚拟机运行中,CPU会从PC中获取将要执行的指令的地址,去该地址执行该指令,完成后,PC会继续下移到下一个指令的位置。
-
JVM Stack:线程栈,栈中存放栈帧,每个线程拥有自己的私有的线程栈空间,线程栈由栈帧构成,每个方法会形成一个栈帧。
栈帧由如下几部分构成: 1、局部变量表 : local variable table 类似于寄存器,存放方法中的参数和变量 2、操作数栈: operand stack ,类似于内存。 所有数据必须都读取进操作数栈才能进行运算,是一个先进先出的栈结构。 主要用于保存计算的中间结果,同时作为计算过程中变量的临时存储空间。 3、动态链接: dynamic Linking。 动态链接是将一个符号引用解析为直接引用的过程。 A(){ c.B(); } 例如 : 当一个方法A中调用了 c类的B方法时 ,需要去常量池中c类 的class结构中找到B方法。当然首先要找到引用的c类, 如果有必要就要加载c类,将符号引用改为直接引用。 这样当再次遇到相同的引用时,可以直接使用这个直接引用, 不用再次解析。 4、返回值地址: return address。 用于存放方法返回值的地址。当需要用到返回值时,就去该地址中获取返回值。
-
Heap : 堆 ,实例化对象的存储空间,线程共享。
分代管理,GC回收的主要区域。
-
Method Area : 方法区。
存放所有的class结构,所有线程共享
a. Perm Space (<1.8) 永久代 在小于1.8时,方法区也叫永久代 i. 字符串常量位于PermSpace FGC不会清理 大小启动的时候指定,不能变 b. Meta Space (>=1.8) 元空间 在大于等于1.8时,方法区被称为元空间 i. 字符串常量位于堆 会触发FGC清理 不设定的话,最大就是物理内存
-
Run-time constant Pool : 运行时常量池,存在于方法区中。
下面再详细介绍 -
Native method Area : 本地方法栈。
是调用系统本地方法的栈空间。
常量池
说到常量池,就在这里顺便总结一下关于常量池的一些相关知识。
常量池分为三种,且均存在于方法区中。
全局字符串池:
全局字符串池里的内容是在类加载完成,经过验证,
准备阶段之后在堆中生成字符串对象实例,然后将该字符串对象实例
的引用值存到string pool中 (string pool中存的是引用值而
不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间存放的)
在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个哈希表,里面存的是驻留字符串(也就是我们常说的用双引号括起来的)的引用(而不是驻留字符串实例本身),也就是说在堆中的某些字符串实例被这个StringTable引用之后就等同被赋予了”驻留字符串”的身份。这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。
class 文件常量池:
这个最好了解一下class文件的结构。
在.class文件中除了包含类的版本、字段、方法、接口等描述信息外,
还有一项信息就是常量池(constant pool table)用于存放编译器
生成的各种字面量(常量)(Literal)和符号引用。
主要包括三种常量:
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
运行时常量池:
jvm在执行某个类的时候,必须经过加载、连接、初始化,
而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,
jvm就会将class常量池中的内容存放到运行时常量池中,由此可知,
运行时常量池也是每个类都有一个
递归调用的压栈和弹出
首先要了解一下有关栈帧的执行过程:
1、一个栈中可以有多个栈帧,栈帧随着方法的调用而创建,随着方法的结束而消亡。
2、该栈帧中存储该方法中的变量,原则上各个栈帧之间的数据是不能共享的,但是在
方法间调用时,jvm会将一方法的返回值赋值给调用它的栈帧中。
3、每一个方法调用,就是一个压栈的过程,每个方法的结束就是一个弹栈的过程。
4、压栈都将会将该栈帧置于栈顶,每个栈不会同时操作多个栈帧,只会操作栈顶,当
栈顶操作结束时,会将该栈帧弹出,同时会释放该栈帧内存,其下一个栈帧将变为栈顶。
5、栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属
线程中可见,即栈内存可以理解成线程的私有内存。
不想画图了,从网上找了一张图,以后有时间再话吧。。。