GC基本概念

来源:互联网 发布:linux客户端是什么意思 编辑:程序博客网 时间:2024/06/12 01:02

我们知道,进行垃圾回收主要分为两个部分:查找需要回收的对象(垃圾收集) 进行实际上的回收操作

GC回收的触发条件

GC主要处理的是对象的回收操作,那么什么时候会触发一个对象的回收的呢?
1. 对象没有引用
2. 作用域发生未捕获异常
3. 程序在作用域正常执行完毕
4. 程序执行了System.exit()
5. 程序发生意外终止(被杀进程等)

垃圾收集的方式

  1. 引用计数器算法

    当创建对象的时候,为这个对象在堆栈空间中分配对象,同时会产生一个引用计数器,同时引用计数器+1,当有新的引用的时候,引用计数器继续+1,而当其中一个引用销毁的时候,引用计数器-1,当引用计数器被减为零的时候,标志着这个对象已经没有引用了,可以回收了


缺点:如果出现循环引用的情况 A.b = B; B.a = A;计数器算法没有办法将其标记为垃圾。造成内存浪费2.根搜索算法

根搜索算法是从离散数学中的图论引入的,程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点

目前java中可作为GC Root的对象有1、 虚拟机栈中引用的对象(本地变量表)2、 方法区中静态属性引用的对象3、 方法区中常量引用的对象4、 本地方法栈中引用的对象(Native对象)说了这么多,其实我们可以看到,所有的垃圾回收机制都是和引用相关的,那我们来具体的来看一下引用的分类,到底有哪些类型的引用?每种引用都是做什么的呢?Java中存在四种引用,每种引用如下:
  1. 强引用
    只要引用存在,垃圾回收器永远不会回收
    Object obj = new Object();
    //可直接通过obj取得对应的对象 如obj.equels(new Object());
    而这样 obj对象对后面new Object的一个强引用,只有当obj这个引用被释放之后,对象才会被释放掉,这也是我们经常所用到的编码形式。
  2. 软引用
    非必须引用,内存溢出之前进行回收,可以通过以下代码实现
    Object obj = new Object();
    SoftReference sf = new SoftReference(obj);
    obj = null;
    sf.get();//有时候会返回null
    这时候sf是对obj的一个软引用,通过sf.get()方法可以取到这个对象,当然,当这个对象被标记为需要回收的对象时,则返回null;
    软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。
  3. 弱引用
    第二次垃圾回收时回收,可以通过如下代码实现
    Object obj = new Object();
    WeakReference wf = new WeakReference(obj);
    obj = null;
    wf.get();//有时候会返回null
    wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾
    弱引用是在第二次垃圾回收时回收,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。
    弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器
  4. 虚引用(幽灵/幻影引用)
    垃圾回收时回收,无法通过引用取到对象值,可以通过如下代码实现
    Object obj = new Object();
    PhantomReference pf = new PhantomReference(obj);
    obj=null;
    pf.get();//永远返回null
    pf.isEnQueued();//返回从内存中已经删除
    虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
    虚引用主要用于检测对象是否已经从内存中删除。

垃圾清理的方式

1.标记-清除算法

标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,因此会造成内存碎片!

2.复制算法

复制算法采用从根集合扫描,并将存活对象复制到一块新的,没有使用过的空间中,这种算法当控件存活的对象比较少时,极为高效,但是带来的成本是需要一块内存交换空间用于进行对象的移动。也就是我们前面提到的
这样解决了内存碎片的问题,但是就是特别耗内存,清理的时候需要两倍的内存

3.标记-整理算法

-整理算法采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题。
或者使用经过多少次清理之后,同一做一次整理,也能避免碎片问题,但是效率较低

垃圾清理执行方式

  1. 串行回收方式( Serial收集器)

    Serial收集器:进行垃圾回收的时候,需要中断所有的用户线程,知道它回收结束为止,因此又号称“Stop The World” 的垃圾回收器
    串行回收方式适合低端机器,是Client模式下的默认收集器,对CPU和内存的消耗不高,适合用户交互比较少,后台任务较多的系统。


ParNew收集器:同样有Stop The World的问题,他是多CPU模式下的首选回收器(该回收器在单CPU的环境下回收效率远远低于Serial收集器,所以一定要注意场景哦),也是Server模式下的默认收集器。

SerialOld:SerialOld是旧生代Client模式下的默认收集器,单线程执行;在JDK1.6之前也是ParallelScvenge回收新生代模式下旧生代的默认收集器,同时也是并发收集器CMS回收失败后的备用收集器。
Serial收集器默认新旧生代的回收器搭配为Serial+ SerialOld

  1. 并行回收方式( ParallelOld收集器)

    ParallelOld是老生代并行收集器的一种,使用标记整理算法、是老生代吞吐量优先的一个收集器。这个收集器是JDK1.6之后刚引入的一款收集器,我们看之前那个图之间的关联关系可以看到,早期没有ParallelOld之前,吞吐量优先的收集器老生代只能使用串行回收收集器,大大的拖累了吞吐量优先的性能,自从JDK1.6之后,才能真正做到较高效率的吞吐量优先

  2. 并发回收方式(CMS)

    CMS又称响应时间优先(最短回收停顿)的回收器,使用并发模式回收垃圾,使用标记-清除算法,CMS对CPU是非常敏感的,它的回收线程数=(CPU+3)/4,因此当CPU是2核的实惠,回收线程将占用的CPU资源的50%,而当CPU核心数为4时仅占用25%。

    CMS
    模式主要分为4个过程
    1.初始标记:需要中断所有用户线程
    2.并发标记
    用户线程和标记线程并发执行,而在这个过程中,随着内存引用关系的变化,可能会发生原来标记的对象被释放,进而引发新的垃圾,因此可能会产生一系列的浮动垃圾,不能被回收。
    3.重新标记
    4.并发清除

引用:http://jbutton.iteye.com/blog/1569746

0 0