JVM内存模型HotSpot 1.8 jvm内存模型
2020-12-28 11:29:11 3 举报
JVM内存模型和垃圾回收
作者其他创作
大纲/内容
方法的行号信息
存活对象
SystemClass Loader
引用计数器
Object obj1 = new Object;
编译器优化技术
ExtensionClass Loader
程序计数器,当前线程所执行的字节码的行号指示器,字节码解释器工作时,通过改变计数器的值,执行下一条指令,此内存是JVM规范中唯一一个没有OutOfMemoryError的区域。
常量池信息
ObjectA
标记-清除算法(Mark-Sweep) 是最早出现也是最基础的垃圾收集算法,分为“标记”和“清除”两个阶段,从根集合(GC Roots)进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的死亡对象进行回收标记回收。主要缺点: 第一执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低。 第二内存空间碎片化问题,标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作
-Xint
即时编译器(JIT)
程序计数器/PC寄存器(线程私有)
类型指针
字节码生成
rc = 1
将前面生成的信息转换为字节码写入磁盘,并进行少量代码的添加和转换
编译器
初始化Initialization
ref
对象Object
TLAB
8种基本类型
加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序进行,而解析阶段则不一定,它在某些情况下可能在初始化阶段后在开始,因为java支持运行时绑定。
Native Method Stacks 为虚拟机使用到的本地(Native)方法服务,本地方法栈也会在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。
不是必然存在,也没有特别的含义,它仅仅起着占位符的作用。HotSpot虚拟机要求对象起始地址必须是8字节的整数倍
CPU
可回收对象
字节码文件
Eclipse JDT中的增量式编译器(ECJ)
Operand StackLIFO
堆用来存放对象,几乎所有(逃逸分析技术,栈上分配、标量替换)对象都在堆上分配,将Java堆细分的目的只是为了更好地回收内存,或者更快地分配内存,堆中没有内存分配对象,并且无法扩展时,会抛出OutOfMemoryError异常
属性表集合
User-DefinedClass Loader
null
将Token流组件转换成更加结构化的语法树
......
语法分析
Class文件的结构
Object obj2 = obj1;
ConstantValue
空闲
版本minorversionmajorversion
本地方法库
HelloWorld
类加载器引用
标记-复制算法(Semispace Copying)
rc = 2
안녕 한 세계
线程私有
验证Verification
obj1
Object4
astore_n
方法区和永久代的关系: 在JDK1.8之前,习惯把方法区称为“永久代”HotSpot 虚拟机在1.7之前使用永久代来管理(实现)方法区,使得jvm的垃圾回收器能像管理堆内存一样来管理永久代这部分内存,而不用专门为方法区编写内存管理代码。但这种设计使得虚拟机更容易出现内存溢出问题,而不像J9和JRockit只要没有触碰到进程可用内存的上限(32位4GB),就没有问题。 JDK1.7把原本放在永久代的字符串常量池、静态变量等移出(主要剩余类型信息) JDK1.8完全废弃了永久代的概念,改用与JRockit、J9一样在本地内存中实现的元空间方法区无法满足新的内存分配需求时,将抛出OutOfMemoryError异常。
方法表
TLAB(线程私有)
15/大对象
逆优化
S0/From
回收后
解释器
标记-复制算法(Semispace Copying):将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。主要缺点: 第一Copying算法的效率跟存活对象的数目多少有很大的关系,如果存活对象很多,那么Copying算法的效率将会大大降低。 第二将可用内存缩小为了原来的一半,空间浪费。
Object2
Survival区与Eden区相同都在Java堆的年轻代。Survival区有两块,一块称为from区,另一块为to区,这两个区是相对的,在发生一次Minor GC后,from区就会和to区互换。在发生Minor GC时,Eden区和Survivalfrom区会把一些仍然存活的对象复制进Survival to区,并清除内存。Survival to区会把一些存活得足够旧的对象移至年老代。
方法信息
加载Loading
Safe Point
为类的静态变量分配内存,并将其初始化为默认值
分代收集算法 Generational Collection(分代收集)是目前大部分JVM的垃圾收集器采用的算法。根据对象存活的生命周期将内存划分为若干个不同的区域
Object
GC分代年龄
你好世界
标记-清除算法(Mark-Sweep)
public class Main { void test() { int a = 1; int b = 2; int c = a + b; System.out.println(c); }}
标注检查
HashCode
javac Main.javajavap -v -p Main.class
OopMap作用:快速找到GC ROOTS,当所有线程停下来的时候,并不需要一个不漏的检查完所有执行上下文和全局引用位置,虚拟机应该是有办法直接知道哪些地方存放着对象引用。在HotSpot的实现中,是使用一组称为OopMap的数据结构来达到目的的。OopMap存储两种对象引用:1、对象内的引用。2、栈、寄存器中引用
$CLASSPATH
Java虚拟机规范,允许虚拟机实现增,在栈帧之中增加一些规范里没有描述的信息,例如与调试、性能收集相关的信息。
HelloWorld.java
数组边界检查消除
源文件
公共子表达式消除
Class实例引用
Windows机器指令
InnerClasses
obj2
编译后 .Class文件的Code属性的max_locals数据记录局部变量表的最大容量
正常调用完成异常调用完成
如果线程请求的栈深度大于虚拟机所允许深度,将抛出StackOverflowError异常;如果Java虚拟机栈容量可以动态扩展 ,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。
准备Preparation
常量池主要存放,字面量(Literal)和符号引用(Symbolic References)字面量:如文本字符串、被声明为final的常量值等。符号引用:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符、方法句柄和方法类型、动态调用点和动态常量
词法分析
使用Using
GC Roots
运行时常量池是方法区的一部分,运行期间将可以手动将新的常量放入池中,如:String的intern()方法;受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。
魔数CA FE BA BE
逃逸分析
新生代
javac 编译
运行期间把常量池中的符号引用转换成直接饮用的过程,叫做动态链接;每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。
栈上分配
类型信息
方法区 CodeCache
字段信息
局部变量槽Slot,64位long、dubbo占两个Slot,其余占一个
STW
类接口的访问标识
基于采样的热点探测
数组长度
Object6
标量替换
本地接口
栈针2(method2)
操作数栈(Operand Stack)
语言处理javacecj
返回地址(Return Address)
Eden
标记完回收前
本地方法栈(线程私有)
方法区(MetaData Space 元空间)/Non-Heap
font color=\"#ff3333\
引用计数算法
Direct Memory(直接内存)
锁状态标志
同步消除
...
String字符串常量池
链接过程负责对二进制字节码的格式进行:校验、解析类中调用的接口、类。校验是防止不合法的.class文件,然后 对类中的所有属性、调用方法进行解析,以确保其需要调用的属性、方法存在,以及具备应的权限(例如public、private域权限等),会造成NoSuchMethodError、NoSuchFieldError等错误信息。
$JAVA_HOME/jre/lib/ext/*.jar
对齐填充
基于计数器的热点探测
a: 1
安全点就是程序能够停顿的位置。即程序不是在任何时候停顿下来进行GC,只有到了安全点才去更新OopMap和停顿,等待GC完成在继续执行。
即时编译器(JIT)编译后的代码缓存
Mac机器指令
aload_n
-Xcomp
提前编译器AOT,直接把程序编译成与目标机器指令集相关的二进制代码
自定义类加载器
确保被加载的类的正确性
类加载子系统
Object1
偏向线程ID
Linux机器指令
こんにちは、世界
填充符号表
溢出
控制流分析
局部变量表
Code
ObjectC
obj1 = null;
数组
Serial GC
GC Root Set
GC Roots的对象:1、在虚拟机栈(栈帧中的本地变量表)中引用的对象,如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。2、在方法区中类静态属性引用的对象,如Java类的引用类型静态变量。3、在方法区中常量引用的对象,如字符串常量池(String Table)里的引用。4、在本地方法栈中JNI(即通常所说的Native方法)引用的对象。5、Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。6、所有被同步锁(synchronized关键字)持有的对象。7、反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
BootstrapClass Loader
栈针N(method...)
在语法树的基础上再做一些处理,如给类添加默认的构造函数,检查变量在使用前是否已经初始化,将一些常量进行合并处理,检查操作变量类型是否匹配,检查所有的操作语句是否可达,检查checked exception是否正确处理。
将Java源文件的字符流转变成对应的Token标记流
Eden区位于Java堆的年轻代,是新对象分配内存的地方,由于堆是所有线程共享的,因此在堆上分配内存需要加锁。而Sun JDK为提升效率,会为每个新建的线程在Eden上分配一块独立的空间由该线程独享,这块空间称为TLAB(Thread Local Allocation Buffer)。在TLAB上分配内存不需要加锁,因此JVM在给线程中的对象分配内存时会尽量在TLAB上分配。如果对象过大或TLAB用完,则仍然在堆上进行分配。如果Eden区内存也用完了,则会进行一次Minor GC(young GC)。
如果对象是数组,有一块用于记录数组长度的数据
卸载Unloading
实例数据
加载class
虚拟机栈(线程私有)
S1/To
对象
Object5
ObjectB
解析Resolution
语义分析
$JAVA_HOME/jre/lib/rt.jar
动态链接(Dynamic Linking)
字节码指令
加载
LocalVariableTable
即时编译
Exceptions
Mark Word
CMS GC
常量池 加载 进方法区运行时常量池
字段计数器和字段表集合
Parallel Scavenge GC
老年代
标记-整理算法(Mark-Compact) 标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存主要缺点: 进过标记后如果有大量存活对象,移动存活对象,并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用程序才能进行 (Stop The World)。
方法计数器和方法表集合
类型常量
ParNew GC
连接
所有收集器在根节点枚举这一步骤时都是必须暂停用户线程“Stop The World”在分析过程中,根节点集合的对象引用关系必须保持不变,即使是号称停顿时间可控,或者(几乎)不会发生停顿的CMS、G1、ZGC等收集器,枚举根节点时也是必须要停顿。
.....
OopMap
HelloWorld.class
局部变量表(Local Variable Table)
数据分析
对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来
把类中的符号引用转化为直接引用
1、将类.class文件中的二进制数据读入到内存中。2、将加载的静态数据结构转化为方法区的运行时数据结构。3、在堆区创建一个Class对象
Parallel Old GC
年老代里存放的都是存活时间较久的,大小较大的对象,因此年老代使用标记整理算法。当年老代容量满的时候,会触发一次Major GC(full GC),回收年老代和年轻代中不再被使用的对象资源
reference类型
Object3
循环引用问题
标记-整理算法(Mark-Compact)
解释执行状态下,将访问最频繁的数据(程序计数器、栈顶)缓存在物理CPU的寄存器中,以此降低对内存的读/写次数,提升执行引擎的执行效率。
对象头
方法内联
额外的信息,如调试信息等
热点代码
Serial Old GC
G1 GC
回收前
栈顶缓存技术
类的继承关系包括类、父类、索引、接口索引集合
编译后 .Class文件的Code属性的max_stacks数据记录操作数栈的最大深度
运行时常量池
b: 2
LineNumberTable
CA FE BA BE 00 00 00 34 00 14 0A 00 03 00 11...
returnAddress
可达性分析/根搜索算法
老年代2/3(old区)
Class信息
Linux 机器指令
执行引擎
新生代/Young区 1/3
运行时数据区
栈针3(method3)
堆 Heap
0 条评论
下一页