java虚拟机(五)--垃圾回收机制GC

时间:2022-12-26 20:57:53

什么样的对象需要回收

  如果对象已经死亡了,就可以进行回收,判断方式如下

  1).引用计数器:给对象添加一个计数器,有地方引用,就+1,当引用失效,就-1。当计数器为0时,判断对象不能再使用,但是当对象相互引

用的时候无法进行GC

  1).可达性算法:从GC Roots开始,到对象之间有引用链相连,就是可达的。HotSpot采用可达性算法,商用虚拟机没有采用引用计数器

GC Roots有哪些:

   1).局部变量表中引用的对象

  2).栈帧中常量引用的对象

  3).栈帧中static引用的对象

  4).JNI引用的对象

  5).类加载器

  6).Thread

垃圾回收算法

  1).标记清除:对不具有可达性的对象进行标记,然后进行统一回收,最基本的GC算法

  缺点:标记和清除两个阶段效率都不高,会产生大量不连续的内存碎片,在给大对象分配内存的时候,可能无法找到连续的内存,而不得不提

前进行GC

  2).复制:把内存分成相同两部分,每次使用一部分,GC的时候把可用对象复制到另一边,然后把使用的一边直接清理掉,不会产生内存碎片,

但是直接浪费了一半内存,代价太巨大了。

  3).标记整理:如果对象存活率比较高的时候,复制算法的效率就会降低,而且需要有额外的空间进行分担担保,老年代就不可能使用对存活

对象进行标记之后,然后把存活的对象都向一端移动,直接清理边界以外的内存

  4).分带收集:当前商用VM采用的GC算法,新生代使用复制算法,老年代使用另外两个。

  商用虚拟机的新生代都是采用复制算法,新生代的对象98%生命周期都很短,每次使用Eden Space和From Survivor,把这两块区域存活的对象

复制到To Survivor,然后清理内存,Eden Space:From Survivor=8:1,这样每次只会浪费10%内存,当To Survivor内存空间不够的时候,使用老年

代。

HotSpot的算法实现

  可达性分析从GC Roots节点找引用链时,会发生GC停顿,是指分析期间停止其他所有的线程,如果分析过程中对象引用关系还在变化,准确性

无法得到保证。

  主流jvm采用准确式GC,HotSpot中通过一组OopMap的数据结构知道哪些地方存放着对象引用,就可以快速、准确完成GC枚举。

  新生代和老生代默认的空间占比分别是是1/3、2/3。

复制算法的执行流程如下

  1、把Eden + From Survivor存活的对象放入To Survivor区;

  2、清空Eden和From Survivor分区;

  3、From Survivor和To Survivor分区交换。

  4、每次在From Survivor到To Survivor移动时都存活的对象,年龄就+1,当年龄到达15(默认配置是15)时,升级为老生代。大对象也会

直接进入老生代。

  老年代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。

方法区回收(jdk1.8之前永久带实现了方法区,而在jdk1.8废弃永久带,通过本地内存实现)

  对方法区回收也可以说是对永久带回收,主要针对两部分:

  1、废弃的常量:例如一个字符串"abc"在常量池中,但是没有任何String对象引用它,进行GC的话,就需要被清理出常量池,类、方法、字段

的符号引用也是相同的

  2、无用的类:

    1).该类的所有实例都已经被GC

    2).加载该类的ClassLoader被GC

    3).该类对应java.lang.class对象没有被任何地方引用,也就是无法通过反射得到该类的方法。

引用:

  就是本身保存的数据是另一块内存的起始地址

分类

  1、强引用:类似于new一个对象对应的引用,只要具有可达性,不会被回收

  2、软引用:软引用关联的对象,在内存溢出发生以前,这些对象会被回收。可以通过SoftReference实现软引用

  3、弱引用:只能活到下次GC之前,当进行垃圾回收的时候,它肯定死了。可以通过WeakReference实现软引用

  4、虚引用:最弱的一种引用关系。为对象设置虚引用唯一目的就是能在对象被GC的时候收到一个系统通知。可以通过PhantPhantomReference实现软引用