概述
文章目录
- 一、GC回收哪些内存区域
- 1.1 堆内存
- 1.2 方法区
- 二、GC如何判断垃圾对象
- 2.1 引用计数法
- 2.2 可达性分析算法(GCRoot)
- 2.2.1 对象引用
- 2.2.2 回收过程
- 三、GC算法
- 3.1 复制回收算法
- 3.2 标记清除算法(Mark-Sweep)
- 3.3 标记整理算法(Mark-Compact)
- 3.4 分代回收算法
- 3.5 GC方式
一、GC回收哪些内存区域
1.1 堆内存
- 对象
- 数组
1.2 方法区
- 垃圾回收性价比低,一般不回收
- 废弃常量:不使用的字符串常量、不使用的符号引用
- 无用的类,同时满足以下三个条件:
1.该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
2.加载该类的ClassLoader已经被回收。
3.该类对应的java.lang.Class对象在任何地方没有被引用,也无法通过反射访问该类的方法。
二、GC如何判断垃圾对象
2.1 引用计数法
Java没有采用这种算法去判断垃圾对象。
- 给对象的对象头中添加一个counter引用计数器,当该对象被引用时,counter+1,当不被引用时,counter-1
- 当对象的counter为0时,则说明该对象没有被引用,也就是垃圾对象。
缺点:容易引起对象之间的互相循环引用,造成死锁状态。
2.2 可达性分析算法(GCRoot)
也叫根搜索算法,Java语言采用这种分析算法去判断垃圾对象。可以作为GCRoot的对象:
- 虚拟机栈(栈帧中的局部变量表)中引用的对象
- 方法区类静态属性引用的对象
- 方法区常量引用的对象
- 本地方法栈中JNl(即一般说的Native方法)的引用的对象。
- 同步锁(synchronized)持有的对象
2.2.1 对象引用
在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference)四种,这四种引用强度依次逐渐减弱。
- 强引用
代码中普遍存在,类似“Object obj=new Object()”这类引用,只要强引用还在,就不会被GC。 - 软引用
非必须的引用,内存溢出时进行回收,如果回收完还不够才抛异常。Object obj = new Object(); SoftReference<Object> sf = new SoftReference<Object>(obj); obj = null; sf.get();//有时候会返回null
- 弱引用
非必须引用,只要有GC,就会被回收。
弱引用是在第二次垃圾回收时回收,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。Object obj = new Object(); WeakReference<Object> wf = new WeakReference<Object>(obj); obj = null; wf.get();//有时候会返回null wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾
弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。 - 虚引用
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。虚引用主要用于检测对象是否已经从内存中删除。
2.2.2 回收过程
第一次标记:使用可达性分析算法分析之后,判断对象不可达。
第二次标记:finalize()方法(上诉或者对象自我救赎的唯一方式)。该方法会被垃圾回收器去调用,并且只会被调用一次。所以可以在finalize方法中,重新建立可达性关联,那么就完成了自我救赎。否则被第二次标记。
三、GC算法
3.1 复制回收算法
Hotspot新生代区域采用这种回收算法,新生代包括:Eden、Survivor1,Survivor2。正常对象内存分配的时候,只会使用Eden区和Survivor其中的一块区域。
使用复制算法垃圾回收的步骤:
1.当Eden空间不足,触发垃圾回收,会将Eden区和其中一块Survivor区域中GCRoot可达的对象复制到另一块Survivor区
2.然后将Eden区和Survivor其中的一块区域中的对象完全清理掉
缺点:内存分配时会浪费新生代10%的空间
当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(HandlePromotion)。
3.2 标记清除算法(Mark-Sweep)
最基本的算法,主要分为标记和清除2个阶段。首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。
缺点:
- 效率不高。
- 产生空间碎片。会产生大量不连续的内存碎片,会导致大对象可能无法分配,提前触发GC 。
3.3 标记整理算法(Mark-Compact)
老年代没有人担保,不能用复制回收算法。可以用标记-整理算法,标记过程仍然与“标记-清除”算法一样,然后让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
3.4 分代回收算法
当前商业虚拟机都是采用这种算法。根据对象的存活周期的不同将内存划分为几块。
- 新生代,每次垃圾回收都有大量对象失去,选择复制算法。
- 老年代,对象存活率高,无人进行分配担保,就必须采用标记清除或者标记整理算法
3.5 GC方式
minorGC:新生代的垃圾回收,很快就回收了,新生代回收的频率高
majorGC:老年代的垃圾回收,比minorGC慢10倍
fullGC:整个JVM的垃圾回收。整个堆(minorGC和majorGC)和方法区的垃圾回收。触发条件:
- system.gc()
- 老年代不够用
- 方法区不够用
- 当新生代的对象无法被老年代担保成功时
最后
以上就是震动抽屉为你收集整理的JVM系列十——GC概述的全部内容,希望文章能够帮你解决JVM系列十——GC概述所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复