1. 如何判断对象为垃圾对象
1.引用计数算法
在很多的地方判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当一个地方引用它时,计数器 就加1;失效时就减1;任何时刻计数器为0的对象是不可能再被使用的。
但是堆栈内部进行了循环引用,说明它已经不存在外部引用了那么此时他的计数器也一样会增加而导致无法为0被收集。
2.可达性分析法
解决引用计数存在的问题,通过引用可到达性来判断这个堆中的对象是否还能存活。一旦栈中的引用失效就可以认为此对象可以回收了。
2. 如何回收
1. 标记-清除算法(老年代)
分为"标记"和“清除”两个阶段:首先标记出所有需要回收的对象,标记完成以后回收所有被标记的对象。
问题:标记时的效率 空间
2. 复制算法(新生代)
适用内存收集效率较高的。它将可用的内存分为两块每次只用其中的一块当这块用完的就将还存活的对象复制到另一块上面然后再把使用过的内存空间一次性清理了。它解决了效率问题但是内存区域却只有原来的一半。所以有了如下算法
对象在新生代中先进入到Ede区域但是这里Eden只有新生代的80%,满了之后会继续到Survivor0中(10%)。进行垃圾回收时会把Eden和Survivor中的进行回收存活一般是10%的则放入到Survivor1中,如果是有更多的存活对象那么会进入Tenured Gen老年代中分配担保。这样可以保证可以使用更多的区域。
3. 标记-整理算法(老年代)
内存收集效率较低的。它和之前的标记-清楚算法的区别是先进行标记然后一一清楚这里加了一步整理的过程。对标记和非标记的对象进行移动统一处理。
4.分代回收算法 = 复制算法 + 标记整理算法
垃圾收集器
由于没有统一的规范所以现在的垃圾收集器较多 新生代GC(Monor GC):指发生在新生代的垃圾收集动作,因为Java对象大多存活率不高,所以Minor GC非常频繁一般回收速度也快。老年代GC (Monor GC/ Full GC):指发生在老年代的垃圾收集动作出现了Major GC。Major GC的速度一般会比Minor GC慢10倍以上。
1. Serial收集器
针对新生代,采用复制算法,单线程收集进行垃圾收集时必须暂停所有的工作线程知道完成。最基本,发展最悠久的单线程。一旦垃圾线程开始运行那么其他的多线程就会停下来,知道垃圾回收线程停止才开始继续执行。当用于客户端环境的时候就很适用。
2. parNew收集器
多线程收集,使用 -XX:ParallelGCthreads 参数来限制垃圾回收的线程数 。
3. Parallel Scavenge收集器
1. 针对于新生代的复制算法 2 . 多线程 3. 控制吞吐量
-XX:MaxGCPauseMills 垃圾收集器停顿时间
-XX:GCTimeRatio 吞吐量大小(0-100)
4. cms收集器
概念: Concurrent Mark Sweep == 标记-清楚算法 (针对老年代)虽然标记清楚算法存在
过程:初始标记 -- 并发标记 -- 重新标记 -- 并发清理
优点:并发收集;低停顿 / 缺点:占用大量的CPU资源并行资源;无法处理浮动垃圾;空碎片
5. g1收集器(garbage first) jdk9默认收集器
优势:1.并行与并发 2.分代整合,针对内存区域进行回收不在分新生代和老年代 3.空间整合 4.可预测的停顿。相比cms更加减少停顿