1,对象没有引用
2,作用域发生未捕获异常
3,程序在作用域正常执行完毕
4,程序执行了System.exit()
5,程序发生意外终止(被杀进程等)
就像图中生成树一样,从一个节点GC ROOT 开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。
GC ROOT 对象包括
1,虚拟机栈中引用的对象(本地变量表)
2,方法区中静态属性引用的对象
3,方法区中常量引用的对象
4,本地方法栈中引用的对象(Native Object)
标记清除
跟搜索标记无用的删除,产生好多碎片
复制算法
再开一个相同大小的内存,吧有用的复制过去,紧密的放置,缺点是新开一块内存
标记整理
有用的往前挪,没有碎片,不用新开区域,就是慢一些
Reference
Reference类是所有引用类型的基类,定义了reference对象的通用操作。
对象新建后默认为强引用类型的,是普遍对象引用的类型。查看FinalReference在JDK中的源码发现其只有一个空实现,这也说明强引用是“默认引用类型”。任何通过强引用所使用的对象都不会被GC回收。是我们经常所用到的编码形式。
** 强可达(Strongly reachable)**
如果一个对象可以被一些线程直接使用而不用通过其他引用对象(reference objects),那么它就是强可达。一个新创建的对象对创建它的线程来讲就是强可达的。
软引用是用来描述一些“还有用但是非必须”的对象。软引用的回收策略在不同的JVM实现会略有不同,JVM不仅仅只会考虑当前内存情况,还会考虑软引用所指向的referent最近的使用情况和创建时间来综合决定是否回收该referent。软引用保存了两个变量:
timestamp:每次调用get方法都会更新时间戳。JVM可以利用该字段来选择要清除的软引用,但不是必须要这样做。
clock:时间锁,由垃圾收集器更新。
软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分软引用数据。
** 软可达(Softly reachable)**
如果一个对象没有强可达性,但是它可以通过一个软引用(soft reference.)来使用,那么它就具有软可达性。
只有当系统需要更多内存时,GC才会回收具有软可达性的对象。在内存不足前,GC保证一定回收软可达的对象。
关于软引用(SoftReference)何时应该被回收的算法依赖于不同的JVM发行版本。它往往是一个跟引用(reference)的使用频率和使用间隔有关的函数。
只要发生GC,弱可达的对象就会被清除,同时会把弱引用加入到注册的引用队列中(如果存在的话)。弱引用对GC几乎是没有影响的,它不影响对应的referent被终结(finalized)和回收(reclaimed)。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器。弱引用最常见的使用情景是通过WeakHashMap。它是一种简单地将对象的生命周期跟Map中对象的索引域(key)绑定的方式。只有当WeakHashMap中的Key是强可达,也就是WeakHashMap中的数据域(Data域)的对象,在应用程序的其他地方有别的引用的时候,它里面的值才不会被回收。一旦应用程序中没有其他对WeakHashMap中对象的引用,那么它的所有的key就会变成弱可达,不需要用户的额外干预,所有WeakHashMap中的对象都会被清除。这是一种优雅地防止内存泄露的方式。
** 弱可达(Weakly reachable)**
如果一个对象既没有强可达性,也没有软可达性,但是它可以通过一个弱引用(weak reference)来使用,那么他就具有弱可达性。当弱引用指向的弱可达对象没有其他的引用,那么这个对象就会被回收。
虚引用是每次垃圾回收的时候都会被回收,完全不会影响该对象的生命周期,也无法通过虚引用来获取一个对象的实例,因此也被成为幽灵引用,能在此对象被垃圾收集器回收的时候收到一个系统通知,检测对象是否已经从内存中删除。
** 虚可达(Phantom reachable)**
如果一个对象既没有强可达性,也没有软可达性、弱可达性,他已经被终结(finalized),并且有一些虚引用(phantom reference)指向它,那么它就具有虚可达性。
不可达(Unreachable)
当一个对象不能通过以上的方式指向,那么这个对象就变得不可达,并因此适合被回收。
收集器是历史最悠久的一个回收器,JDK1.3之前广泛使用这个收集器,目前也是ClientVM下 ServerVM 4核4GB以下机器的默认垃圾回收器。单线程收集器,没有线程交互的开销,进行垃圾回收的时候,需要中断所有的用户线程。
SerialOld是老年代Client模式下的默认收集器,单线程执行。
串行回收方式适合低端机器,是Client模式下的默认收集器,对CPU和内存的消耗不高,适合用户交互比较少,后台任务较多的系统。
Serial收集器默认新旧生代的回收器搭配为Serial+SerialOld
ParNew收集器其实就是多线程版本的Serial收集器,其他的都和Serial一样,进行垃圾回收的时候,需要中断所有的用户线程。
他是多线程模式下的首选回收器,也是Server模式下的默认收集器。
ParallelScavenge又被称为是吞吐量优先的收集器
所提到的吞吐量=程序运行时间/(JVM执行回收的时间+程序运行时间),假设程序运行了100分钟,JVM的垃圾回收占用1分钟,那么吞吐量就是99%。在当今网络告诉发达的今天,良好的响应速度是提升用户体验的一个重要指标,多核并行云计算的发展要求程序尽可能的使用CPU和内存资源,尽快的计算出最终结果,因此在交互不多的云端,比较适合使用该回收器。
ParallelOld是老生代并行收集器的一种,使用标记整理算法、是老生代吞吐量优先的一个收集器。这个收集器是JDK1.6之后刚引入的一款收集器,我们看之前那个图之间的关联关系可以看到,早期没有ParallelOld之前,吞吐量优先的收集器老生代只能使用串行回收收集器,大大的拖累了吞吐量优先的性能,自从JDK1.6之后,才能真正做到较高效率的吞吐量优先。
用于老年代收集,使用基于标记-清除算法实现。并发收集、低停顿。为了减少回收停顿时间。
执行分为4步:
初始标记:标记GC Roots能直接到的对象。速度很快但是暂停其他线程。
并发标记:进行GC Roots Tracing 的过程,找出存活对象且用户线程可并发执行。
重新标记:暂停其他线程,修正并发标记期间因用户程序继续运行而导致标记变动。
并发清除:对标记的对象进行清除回收。
CMS收集器的内存回收过程是与用户线程一起并发执行的。
G1收集器的工作范围是整个Java堆,不同的方式去处理新老对象,在使用G1收集器时,它将整个Java堆划分为多个大小相等的独立区域(Region)。虽然也保留了新生代、老年代的概念,但新生代和老年代不再是相互隔离的,他们都是一部分Region(不需要连续)的集合。
G1运作期间不会产生空间碎片,收集后能提供规整的可用内存。
G1维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region,建立可预测的停顿时间模型。
执行步骤与CMS一样。