JVM

68 阅读6分钟
GC如何判断哪些对象可以被回收

引用计数法:每个对象都有一个引用计数属性,新增一个引用时计算加1,引用释放时引用减1,计数为0时可以回收
可达性分析算法:从GC Roots根开始向下搜索,搜索所走的路径称为引用链,当一个对象到GC Roots没有任何引用链时,则证明这个对象是不可用的,虚拟机就判断这个对象可以回收

引用计算法,可能会出现A引用B,B引用A,这时候就算它们不再使用了,但因为相互引用,计数器=1,永远无法被回收

GC Roots的对象有:

  1. 虚拟机栈(栈帧中本地变量表)中引用的对象\
  2. 方法区中类静态属性引用的对象\
  3. 方法区中常量引用的对象\
  4. 本地方法栈中JNI(即一般说的Native方法)引用的对象
JAVA类加载过程
JAVA的类加载器

AppClassloader->ExtClassloader->BootstrapClassloader
BootstrapClassloader默认负载加载%JAVA_HOME%/lib下的jar包和class文件
ExtClassloader负载加载%JAVA_HOME%/lib/ext文件夹下的jar包和class文件
AppClassloader负载加载classpath下的类文件
每个类加载器对它加载过的类都是有缓存的
双亲委派机制:当收到一个类加载的请求时,首先加载器先委托父类加载加载,如果还是加载不了,就自己加载
作用:核心类不会被篡改

类加载过程

加载-》链接-》初始化
虚拟机把class文件加载到内存,并对数据进行校验,准备,解析和初始化,形成虚拟机可以使用的Java类型
加载
通过类的全限定名获取这个类的二进制字节流
将这个字节流所代表的静态存储结构转换为方法区运行时数据结构
在Java堆中生成一个代表这个类的Class对象,做方法区的数据访问入口
链接
验证
保证加载类的正确性

  • 文件格式验证
  • 元数据验证
  • 字节码验证
  • 符合引用验证
    准备

为类的静态变量分配内存,并将其初始化默认值
private static int a = 1; 这个阶段a=0
解析
把类中符号引用转换成直接引用 把文件里的引用关系落到内存中的引用关系
初始化
执行class init方法,为静态变量赋值,同时初始化静态代码块,初始化当前类的父类\

一个对象从加载到JVM,再到被GC清除,都经历了什么过程?

用户创建一个对象,JVM需要到方法区去找对象的类型信息,然后再创建对象
JVM要实例化一个对象,首先在堆中创建对象 半初始化状态
对象首先会分配到新生代中的Eden区,然后经过一次Minor GC,如果对象存活,就会进入S区,在后续的GC中,如果对象一直存活,就会在S区来回拷贝,每移动一次,年龄加1
当年龄超过15岁后,对象依然存活,对象进入老年代
经过Full GC,被标记为垃圾对象,就会被GC线程清理掉

JVM中哪些是数据共享区

堆、方法区

JVM有哪些垃圾回收器

Stop-the-World,简称STW

指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应, 有点像卡死的感觉,这个停顿称为STW

Serial 串行

需要GC时,直接暂停,GC完了再继续

Parallel并行

在串行的基础上,增加多线程GC\

Parallel Scavenge+Parallel old是JDK1.8默认的垃圾收集器

CMS(Concurrent Mark Sweep)

初始标记:STW 只标记出根对象直接引用的对象
并发标记:继续标记其它对象,与应用程序是并发标记
重新标记:STW 对并发执行阶段的对象进行重新标记
并发清除:并行,将产生的垃圾对象清除。在清除过程中,应用程序会不断产生新的垃圾,叫做浮动垃圾

G1

在内存模型中,对于堆内存不再存在年轻代和老年代,而是划分一个一个小的内存块,叫做Region,每个Region可以隶属于每个年代
GC分为四个阶段
第一:初始标记,标记出GC Root直接引用的对象
第二:标记Redion,通过RSet标记出上个阶段标记的Region引用到old区的Region
第三:并发标记,跟CMS步骤是差不多的,只是遍历范围不再是整个Old区,而是遍历第二步标记出来的Region
第四:重新标记,跟CMS中重新标记差不多
第五:垃圾清理,跟CMS不同的是,G1可以采用拷贝算法,直接将Region中的对象拷贝到另一个Region,而这个阶段,G1只选择垃圾较多的清理,并不是完全清理

三色标记

CMS的核心算法是三色标记
每个内存分三种颜色
黑色:表示自己和成员变量都已经标记完
灰色:自己标记完了,成员变量没有完全标记
白色:自己未标记完

JVM有哪些垃圾回收算法

MarkSwaap垃圾清除算法
这个算法分为两个阶段
标记阶段:把垃圾对象标记出来
清除阶段:直接将垃圾对象清除
这个算法会产生大量的内存碎片
Copying复制算法
将内存分为大小相等的两半,每次只使用一半,垃圾回收时,将当前这一块存活的对象全部拷贝到另一半,当前这一块内存直接清除
这种算法没有内存碎片,会导致浪费空间,它的效率和存活对象有关,存活对象多则效率低
MarkCompack标记压缩算法
为了解决复制算法的缺点,这种算法在标记阶段和标记清除算法一致,在完成标记之后不是直接清除垃圾内存,而是将存活对象往一端移动,然后将端边界以外的所有内存直接清除

JVM垃圾回收器使用哪些垃圾回收算法

Serial 新生代使用复制算法 优点:简单高效,单线程,没有上下文切换 缺点:会在用户不知道的情况下停止用户线程,体验差
ParNew 新生代使用复制算法 低停顿 优点:多核cpu性能高于Serial 缺点:在单核cpu性能没有Serial性能更好
Parallel Scavenge 新生代使用复制算法 优点:追求高吞吐量,高效利用CPU,是吞吐量优先,且能进行精确控制 缺点:存在停顿
Serial Old 老年代使用复制算法
Parallel Old 老年代使用复制算法
CMS(Concurrent Mark Sweep) 老年代 标记清除算法 优点:并发收集,低停顿 缺点:在清除阶段,用户线程还在运行,会产生浮动垃圾,因为使用标记清除算法,会产出内存碎片
G1 不存在年轻代和老年代,整个内存回收,复制算法 优点:并行和并发,分代收集,空间整合,可预测停顿