定义
没有任何一个引用指向的一个或多个对象(环状互相引用)
如何定位垃圾回收
引用计数法:
对象上数字记录有多少引用指向它。
对于环状循环引用此方法有问题。「每个对象引用数都为1」
根可达性分析法:
通过根引用能够到达的对象,不是垃圾。否则就是。
根【GCRoot】包括线程栈变量、静态变量、常量池、JNI指针
垃圾回收算法
- mark-sweep「标记清除」
找出垃圾,标记之后进行清除。
缺点:位置不连续,产生碎片。 - copying「拷贝」
优点没有碎片,效率高。缺点浪费空间。
存储区域一分为二,将存活对象复制到未使用区域,然后可回收区域全部清空。两个区域间来回拷贝。 - mark-compact「标记压缩」
优点:不浪费空间,没有碎片。缺点:效率偏低。
将可回收对象标记,之后将后边存活对象移动到可回收对象位置,即标记清除的过程中,进行了一次压缩、整理。
效率低的原因:压缩的过程,内存挪动,如果是多线程要涉及到线程同步。
分代模型【分代回收算法】
新生代
包括eden区+2个survivor区
进行一次垃圾回收【YGC/YoungGC/MinorGC】以后,大多数对象「80-90%」都会被回收。
采用的是复制copy算法(效率高)「所以存在两个surviror区」
过程:
- new一个对象后,默认会找eden区,如果对象特别大,直接进入老年代。
- 第一次YGC后,大多数对象会被回收,eden区的存活对象会被拷贝到survivor0。清空eden区
- 下次YGC,eden区以及survivor0区存活的对象进入survivor1区。清空eden和survivor0区
- 再次YGC,将eden区和survovor1区存活的对象拷贝进入survivor0区,清空eden区和survivor1区
- 就这样,来回拷贝。
回收多次该对象还存活【年龄足够】 或者 eden->survivor时survivor存不下,放入old区。老年代兜底,老年代不会频繁GC。
年龄足够「CMS是6岁,古老的回收器是15岁」
老年代
装着的是顽固分子,满了会触发FullGC【majorGC】
FullGC:新生代和老年代整体发生GC,会发生StopTheWorld「停顿现象」。内存越大停顿越长。
回收算法采用的是拷贝压缩mark compact,算法效率低。
调优
尽量减少FGC
常见垃圾回收器
- Serial 用于年轻代,串行回收「单线程回收,回收线程是一个线程」
- ParalleScavenge 用于年轻代,并行回收「多线程回收,回收线程是多线程」
- SerialOld 用于老年代,串行回收
- ParalleOld 用于老年代,并行回收
- CMS「ConcurrentMarkSweep」用于老年代,并发的「垃圾回收线程和应用程序线程可以同事运行,降低STW的时间(200ms)」
- G1「10ms」、ZGC「1ms」