文章目录
一、什么是垃圾
没有任何引用指向的一个对象或者多个对象(循环引用)
二、GC垃圾回收主要作用的区域
每个线程都会有自己独有的虚拟机栈、程序计数器、本地方法栈,一旦线程运行结束,这些空间全部被回收掉
使用new关键字创建的对象会进入堆中,堆是线程共享的,线程运行结束后,在堆中创建的对象还保留着,GC主要回收堆中的东西
三、JVM是如何定位垃圾对象的
Java运行时内存区域堆中存放着几乎所有的对象实例,垃圾回收器在堆进行垃圾回收前,首先要判断这些对象哪些还存活,存在引用,哪些已经无引用,称为了垃圾,判断对象是否是垃圾常见有两种算法
3.1 引用计算法
- 引用计算法的定义
给对象增加一个引用计算器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻引用计数器为0的对象就是不能再被使用的,即对象成为了垃圾
- 引用计算法的特点
引用计数法实现简单,判断效率也比较高,在大部分情况下都是一个比较好的算法,Pyhton就选用引用计算法作为定位垃圾的算法。但是,在主流的JVM中没有选用引用计数法来管理内存,最主要的原因是引用计数法无法解决对象的循环引用问题,造成内存泄漏。
3.2 可达性分析法
- 可达性分析法的定义
此算法的核心思想:通过一系列称为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达时),证明此对象不可用。
-
GC Roots对象的种类
-
虚拟机栈(栈帧中的本地变量表)中引用的对象
-
方法区中静态属性引用的对象
-
方法区中常量引用的对象
-
本地方法栈(Native方法)引用的对象
-
-
可达性分析法的特点
主流的JVM选用可达性分析法来管理内存的,除此之外,像C++,Lisp等语言都选用也都选用此算法
四、JVM垃圾回收算法
4.1 标记清除算法
- 标记清除算法的定义
标记清除算法是最基础的收集算法。算法分为标记和清除两个阶段,首先标记处所有需要回收的对象,在标记完成后统一回收所有被标记的对象,不回收的对象继续保留在原来的内存空间中。后续的收集算法都是基于这种思路并对其不足加以改进而已。
- 标记清除算法的特点
标记清除算法的不足之处主要有两个:
-
效率问题:标记和清除这两个过程的效率都不高
-
空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发下一次垃圾回收
4.2 复制收集算法
- 复制收集算法的定义
复制收集算法是为了解决标记清除算法的效率问题,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这块内存需要进行垃圾回收时,会将此区域还存活的对象复制到另一块内存上面,然后再把已经使用过的内存区域一次清除掉。
-
复制收集算法的特点
- 优点
这样做的好处每次都是对整个半区进行内存回收,内存分配时也就不需要考虑内存碎片等的复杂情况,只需要移动堆顶指针,按顺序分配即可
此算法实现简单,运行高效
- 缺点
在空间资源上浪费,浪费了一半的内存空间
在对象存活率较高时会进行比较多的复制操作,效率会变低
4.3 复制整理算法
- 复制整理算法的定义
复制收集算法在对象存活率较高时会进行比较多的复制操作,效率会变低,因此在老年代一般不能使用复制收集算法。老年代里面的对象是不容易成为垃圾的,存活率较高,针对老年代的特点,提出了一种称之为标记整理算法。标记整理算法的标记过程仍与标记清除算法过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象向一段移动,然后直接清理掉端边界以外的内存
-
复制整理算法的特点
- 优点
垃圾回收之后的内存空间是连续的
- 缺点
效率还没有标记清除算法快,因为它比标记清除算法还多了一步整理的步骤
五、JVM的分代回收算法
JVM运行时数据区-堆中分成了新生代和老年代
5.1 新生代
新生代使用的垃圾回收算法是复制收集算法,并对复制收集算法进行了优化。新生代分为3块区域,eden区、servivor0区和servivor1区,它们之间的空间大小比例为8:1:1。在新生代发生的GC称之为Minor GC或者Young GC。
- Minor GC/Young GC的过程
- 正常新创建的对象会直接进入eden区,当eden区内存满了时,触发Minor GC。
- 首先对eden区存活的对象通过可达性分析法进行识别,并对其进行标记
- 将eden区中存活的对象和servivor0中的对象复制到servivor1中
- 对eden区中的垃圾进行清除
- 当下一次Minor GC来临时,先执行步骤2,再将eden区中存活的对象和servivor1中的对象复制到servivor0中,最后执行步骤4,以此类推
- 每经过一轮Minor GC,存活的对象年龄+1,在满了15时,对象直接进入老年代
5.2 老年代
老年代使用的垃圾回收算法是标记整理算法,在新生代发生的GC称之为Full GC/Major GC,老年代中的对象不容易“死亡”,老年代回收垃圾时,JVM会停止运行,尽可能的去避免发生Full GC
- Full GC/Major GC的过程
- 新生代的对象在年龄足够或新生代中存放不下的大对象进入老年代中
- 当老年代中的内存满了时,触发Full GC
- 首先对eden区存活的对象通过可达性分析法进行识别,并对其进行标记
- 然后让所有存活对象向一段移动
- 最后直接清理掉端边界以外的内存
六、常见的垃圾收集器
6.1 新生代垃圾收集器
-
Serial
- 特点
串行回收
- 工作过程
当新生代中内存满了触发minor GC,先停止所有的工作线程,垃圾回收的单线程回收完垃圾后,工作线程继续,以此循环
-
Parallel Scavenge(简称PS)
- 特点
并行回收
- 工作过程
当新生代中内存满了触发minor GC,先停止所有的工作线程,垃圾回收的多个线程同时进行回收垃圾,回收完垃圾后,工作线程继续,以此循环
-
ParNew
- 特点
配合CMS的并行回收,PS不能搭配CMS进行垃圾回收,ParNew可以搭配CMS进行垃圾回收
- 工作过程
和PS的工作过程一样
6.2 老年代垃圾收集器
-
Serial Old
- 特点和工作过程
和Serial一样,作用区域在老年代
-
Parallel Old
- 特点和工作过程
和PS一样,作用区域在老年代
-
Concurrent Mark Sweep(简称CMS) 并发的,
- 特点和工作过程
垃圾回收和应用程序同时运行,降低STW的时间(200ms)
6.3 其他垃圾收集器
-
G1(10ms)
-
ZGC (1ms) PK C++
-
Shenandoah
-
Eplison
JDK1.8默认的垃圾回收:PS + Parallel Old