1.判断对象已死:
(1)引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它,计数器值加一;当引用失效,值减一,任何时刻值为0时对象就是不可能再被使用的。这算法有缺陷很难解决对象之间相互循环引用的问题。
(2)根搜索算法:通过GC Roots的对象作为起始点开始向下搜索,所走的路径为引用链,当一个对象到GC Roots没有任何引用链相连时,对象不可用。
2.刚刚说的GC Root,有哪些对象可以当做GC Root呢?
1.虚拟机栈(栈帧中的本地变量表)中的引用的对象
2.方法区中的类静态属性引用的对象
3.方法区中的常量引用对象
4.本地方法栈中JNI(native方法)的引用的对象
3.引用:
(1)强引用:只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。
(2)软引用:有用但不是必需的对象。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
(3)弱引用:用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。只能生存到下一次垃圾收集发生之前。
(4)虚引用:设置虚引用的唯一目的就是希望能在这个对象被收集器回收时收到一个系统通知。
4.GC回收的对象:
GC Roots搜索不到的对象回进行第一次标记并且进行一次筛选,看是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或finalize()方法已经被虚拟机调用过就没必要。有必要的会放在F-Queue队列中,GC对F-Queue队列中的对象进行第二次标记,如果没复活的对象就会被回收。
5.垃圾收集算法:
(1)复制算法:把堆内存分成2分,每次gc, 把一块内存的存活的对象复制到另一块,然后清空这一块内存,这个可以利用的空间减少了一半。新生代采用复制算法,内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。HotSpot虚拟机默认Eden和Survivor的大小比例为8:1。
优点:解决标记-清除算法效率问题 缺点:浪费空间
(2)标记-清除算法 两缺点:1.效率问题2.空间问题
(3)标记-整理算法 老年代使用
(4)分代收集算法 按对象的存活周期把内存分成几块
6.垃圾收集器
新生代主要有哪些收集算法(Serial、ParNew、Parallel Scvenge)
老年代主要的收集算法(Serial Old、Parallel Old、CMS)
Serial(串行GC)收集器
Serial收集器是一个新生代收集器,单线程执行,使用复制算法。它在进行垃圾收集时,必须暂停其他所有的工作线程(用户线程)“Stop The World”。是Jvm client模式下默认的新生代收集器。对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。
ParNew收集器其实就是serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为与Serial收集器一样。老年代。
Parallel Scavenge收集器也是一个新生代收集器,它也是使用复制算法的收集器,又是并行多线程收集器。parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而parallel Scavenge收集器的目标则是达到一个可控制的吞吐量。吞吐量= 程序运行时间/(程序运行时间 + 垃圾收集时间),虚拟机总共运行了100分钟。其中垃圾收集花掉1分钟,那吞吐量就是99%。
Serial Old是Serial收集器的老年代版本,它同样使用一个单线程执行收集,使用“标记-整理”算法。主要使用在Client模式下的虚拟机。
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。CMS收集器是基于“标记-清除”算法实现的,整个收集过程大致分为4个步骤:
①.初始标记(CMS initial mark)
②.并发标记(CMS concurrenr mark)
③.重新标记(CMS remark)
④.并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤任然需要停顿其他用户线程。初始标记仅仅只是标记出GC ROOTS能直接关联到的对象,速度很快,并发标记阶段是进行GC ROOTS 根搜索算法阶段,会判定对象是否存活。而重新标记阶段则是为了修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间会被初始标记阶段稍长,但比并发标记阶段要短。
CMS收集器的优点:并发收集、低停顿,但是主要有三个显著缺点:
CMS收集器对CPU资源非常敏感。在并发阶段,虽然不会导致用户线程停顿,但是会占用CPU资源而导致引用程序变慢,总吞吐量下降。CMS默认启动的回收线程数是:(CPU数量+3) / 4。
CMS收集器无法处理浮动垃圾,可能出现“ConcurrentMode Failure“,失败后而导致另一次Full GC的产生。
最后一个缺点,CMS是基于“标记-清除”算法实现的收集器,使用“标记-清除”算法收集后,会产生大量碎片。空间碎片太多时,将会给对象分配带来很多麻烦,比如说大对象,内存空间找不到连续的空间来分配不得不提前触发一次Full GC。为了解决这个问题,CMS收集器提供了一个-XX:UseCMSCompactAtFullCollection开关参数,用于在Full GC之后增加一个碎片整理过程。
G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。还有一个特点之前的收集器进行收集的范围都是整个新生代或老年代,而G1将整个Java堆(包括新生代,老年代)划分区域,优先回收垃圾最多的区域。
7.内存分配
(1)对象优先在Eden分配,当Eden区没有足够空间将发起一次Minor GC
(2)大对象直接进入老年代(大量连续内存空间的java对象(很长的字符串及数组))
(3)长期存活的对象将进入老年代 对象年龄计数器,一次Minor GC后并能移到survivor空间年龄就加一。
Minor GC时,检测每次晋升到老年代的平均大小是否大于老年代剩余空间,大于就Full GC,小于先查看HandlePromotionFailure设置是否允许担保失败,允许进行Minor GC,不允许进行Full GC。