1.线程共享

1.1-堆
堆中主要存放对象实例,jdk8后移除永久代,改为使用本地内存的原空间来实现方法区,而字符串常量池留在了堆中。 对于堆,细分为一个Eden区和两个Survivor区。
- 新生代
又分为一个eden区和两个survivor区。新创建的对象实例总是在eden区中为其分配内存,Eden区满后则会触发Minor GC,存活的对象实例会存放到survivor1区中,再次GC后则将剩余存活对象移动到survivor2区中。 - 老年代
- 经过多次GC仍然存活的对象会进入老年代,默认为15次Minor GC
- 动态年龄判断:如果在Survivor空间中相同年龄的对象大小总和大于Survivor空间的一半(即众数),则年龄大于会等于该年龄的对象进入老年代
- 大对象直接进入老年代
- 空间担保策略,老年代在空间不足时会触发Full GC。在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间或者历次晋升的平均大小,如果是则进行Minor GC,如果不是则进行Full GC
1.2-方法区
方法区存放类加载的原始数据结构,又名no heap(”非堆“)
- jdk1.7之前,方法区由永久代实现,永久代和堆相互隔离,永久代的大小在启动JVM时可以设置一个固定值。因为永久代使用虚拟机内存,容易造成内存溢出
- jdk1.8之后,方法区改为原空间实现,使用本地内存。将字符串常量池移动到堆区中
2.线程隔离

2.1-程序计数器
在程序运行过程中,cpu资源需要在多个线程之间切换,而程序计数器则用来保存在线程切换时该线程中指令运行到的位置,以便在线程重新分配到cpu资源时能够在切换时运行到的位置继续执行
2.2-虚拟机栈
虚拟机栈中存放的是一个一个栈帧,每个栈帧对于一个方法的执行
- 栈帧结构
- 局部变量表
存放方法的形参和局部变量,同时局部变量表中的变量也是重要的垃圾回收节点,被局部变量表直接或间接引用的对象不会被GC回收 - 操作数栈
不存在垃圾回收,只有出栈和入栈,分为定义操作,加载操作,计算操作,保存操作等,指令集有:const指令,load指令,add指令,mul指令,store指令等。 - 方法返回地址
方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行 - 动态链接
每一个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用。
- 当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译期可知且运行期保持不变时,这种情况下将调用方法的符号引用转换为直接引用的过程,称为静态链接。
this.say(); - 如果被调用的方法在编译期无法被确定下来,也就是说只能够在程序运行期将调用方法的符号引用转换为直接引用,
由于这种转换过程具备动态性,因此也被称为动态链接。 Animal dog = AnimalFactory.create("dog"); dog.Say(); - 栈和堆的区别
- 堆管存储,栈管运行
- 栈保存局部变量–>8种基本数据类型
- 所有的对象实例存储在堆中,栈中保存对堆中对象实例的引用
- 栈不存在垃圾回收
2.3-本地方法栈

本地方法栈用于执行程序中的native方法。 任何本地方法接口都会使用某种本地方法栈。当线程调用Java方法时,虚拟机会创建一个新的栈帧并压入Java栈。然而当它调用的是本地方法时,虚拟机会保持Java栈不变,不再在线程的Java栈中压入新的帧,虚拟机只是简单地动态连接并直接调用指定的本地方法。
|