什么是GC?
Garbage Collection垃圾收集器,是Java语言中垃圾回收的实现,是对内存管理的一种功能,用于释放无效对象并回收内存。
垃圾回收的标准?
常见的垃圾回收机制主要有两种算法,一种是采用引用计数法(例如Python),另一种是可达性分析算法(Java就是采用的这一类),可达性分析是以GCRoot为根起点线性判断,能关联的对象均视为存活对象,不做垃圾处理,值得一提的是,引用计数无法解决循环引用的垃圾对象。
Java中的引用分类?
我们都知道如果一个对象(或者是一个空间)还有引用指向他,那么虚拟机就会认为是存活对象,在Java中,引用是如何分类的呢?主要有四类,分别是:
强引用:
强引用一般是指用户自定义的对象类型,也就是满足Object obj= new
object();类型的,说白了就是new出来的,这样的对象,宁愿出现OOM也不会回收,若想对其进行回收操作,可以将其赋值为Null。
弱引用:
此类引用就是指垃圾回收机制下判定为垃圾的对象,会被弱引用所指向,这种引用不管内存空间的状态,满足条件就会被回收,属于非必要的对象类型。
软引用:
被软引用指向的对象一般是有用但是非必要的对象,在OOM之前,一般会对其进行二次回收,二次回收结束如果内存依然不足,则会抛出OOM异常,此类对象一般可能是网页缓存,图片缓存等内存敏感的高速缓存对象。
虚引用:
一般用Java.lang.ref.PhantomReference类表示的,这一类的引用相当于没有引用指向,属于随时可以被回收的垃圾对象。
注意:
一个对象的死亡至少要经历两个标记阶段,具有筛选过滤的过程
GC的作业区域?
一般来讲主要是针对JVM虚拟机内存结构空间中的堆空间,那么关于方法区会被回收吗?由于方法区的空间特点是直接与内存相关的,其垃圾回收效率会比其他的低,在规范的讲解上是可以抛出OOM异常的,但是在实际过程中,部分内存的垃圾,也是可以进行垃圾回收的:
1.废弃的常量
2.无用的类
垃圾回收空间介绍:
既然垃圾回收主要针对的是堆空间,那么是怎样实现的呢?主要采用的是分代模型,但是一些更新的垃圾回收器采用的有分区模型(例如:G1,ZGC),本文主要介绍分区模型(即新生代和老年代),如图:
新生代又分为伊甸园区和幸存者区,幸存者区主要是为复制算法所开辟的(下文会有介绍),如果按照伊甸园区、From、To和Old的顺序来分配空间比例,以30M为例,一般比例是8:1:1:20。
垃圾回收算法介绍
1.标记清除算法(Mark–Sweep)
图片展示了清除的过程和效果,此类算法的缺点是会产生空间碎片,空间利用率相比之下会较低。
2.标记整理(Mark–Compact)
此类算法的思想是在垃圾回收后加上了空间整理的过程,相比标记清除,不会产生空间碎片,空间利用率会相对较高,但是由于存在整理的过程,其效率方面会有所下降。
3. 复制算法(Copying)
此类算法不会产生空间碎片,但是会造成额外空间的浪费,因为他需要一个额外空间来存放被复制的垃圾。
总结:
一般来讲,新生代的垃圾回收算法都是采用的复制算法,这也就不会对幸存者区域的存在感到好奇了,一般垃圾回收的过程是:首先垃圾回收器先将垃圾放入到伊甸园区,如果满了,则会放入幸存者区,幸存者区域会对垃圾的生命周期做统计,默认From与To之间GC15次就会被放入老年代。
像有一些大型的对象垃圾,由于内存问题,会被直接放入老年代GC。我们可以通过JMap - histo命令结合dump堆内存文件查看与GC相关的参数。
垃圾回收器的简单介绍
这里借鉴网上的一张关系图来讲解一下,图片表示的是老年代与新生代垃圾回收器的搭配使用,值得注意的是ParNew不可以与Parallel Old搭配使用;其次:Serial系列是属于单线程的,Parallel系列是属于多线程的,G1heCMS都是后来的优化和加强,其主要参数还是体现在STW时间上的缩短,多见于高并发。
几个名词解释
吞吐量:
是指用户代码执行时间和用户代码执行时间与垃圾回收时间的加和比;即(用户代码执行时间)/(垃圾回收时间+用户代码执行时间)
并行(Parallel)
指的是多个垃圾收集器的线程。
STW
Stop The World 即在垃圾回收收时用户线程阻塞,会出现卡顿的现象,形象的比喻,计算机世界的静止。
并发(Concurrent)
在新的垃圾回收器上,除了第一次垃圾标记,在后续的垃圾检查已经实现了与用户代码(线程)同时执行的情况(即不存在STW),这个过程就是并行的过程;
CMS
Concurrent Mark Sweep
Full GC
这是比较严重的现象,是指GC回收空间满,出发的一次”大扫除“,如果频繁出现此类情况,就要检查是否有内存泄漏或是多线程处理上是否有问题。