1、哪些内存需要回收?
GC主要自动回收堆内存(方法区也会被回收,如果大量使用反射等需要回收)
判断对象回收的方式:
1)引用计数器
python等语音使用,实现简单,判定效率高,但是存在循环引用问题
**2)可达性分析(java、c#)**
GC Roots作为起始节点
如果对象引用链无法达到GC Roots则认为对象不可用
引用?
强引用
只要引用还在,就不会被回收
软引用(SoftReference)
描述一些有用但非必需的对象。
系统发生内存溢出之前,将这些对象列入回收范围内,进行二次回收,如果内存还是不够,则抛出内存溢出异常
弱引用(WeakReference)
在下一次垃圾回收时,必定被回收。
虚引用(PhantomReference)
仅用于在对象被回收时,会获取到系统通知。;
2、什么时候回收?
**回收判定:二次标记**
1)如果对象在可达性分析中不可达,被第一次标记
2)对标记对象进行筛选
1》如果对象没有重写finalize()方法或者重写后的方法已被调用过一次
则直接回收
2》如果对象重写finalize()方法并且没有调用过
1>将对象加入F-Queue中
2>另开一个低优先级线程去执行对象的finalize()方法(另起线程是为了防止F-Queue无限等待)
3)对F-Queue中对象,进行二次标记,如果对象引用链可达GC Roots,则移除回收集合,否则将被回收
3、怎么回收?
垃圾收集算法:
1)标记-清除算法
最基础的算法
效率低、回收内存不连续导致内存碎片
2)复制算法
将内存分成两块,每次仅使用其中一块内存,回收时,将其复制到另一块,清除上一块内存
实现简单、效率高、内存连续
将内存缩小,有代价
**此算法用来收集新生代对象,因为新生代对象都是“朝生夕死”**
不需要按照1:1来划分内存,而是分为较大的Eden和两块小的Survivor,将Eden以及一块Survivor中的对象复制到另一块Survivor,然后清理
HotSpot中默认为8:1
3)标记-整理算法
**老年代对象回收算法**
标记过程与标记-清除算法过程一致,但是不在清除,而是将存活的对象向一段移动,然后清除边界外的内存。
4、垃圾收集器
垃圾收集算法是方法论,收集器就是具体实现。
1)Serial收集器
新生代收集器
单线程
“stop the world” 垃圾收集时,必须暂停其他工作线程,如果耗时长,体验差
client模式下默认的新生代收集器
优点:简单高效、没有线程开销
2)ParNew收集器
多线程版本的Serial收集器
除了Serial之外唯一可与CMS配合的新生代收集器
开启线程数默认与CPU数量相同
3)Parallel Scavenge收集器
新生代收集器,使用复制算法,并行多线程
实现目的是达到一个可控的吞吐量,即用户代码运行时间占用总时间的比率
停顿时间越短,用户体验越好,而高吞吐量可以高效的利用CPU时间,尽快完成运算任务,适合多运算少交互的任务。
吞吐量优先的收集器
4)Serial Old收集器
老年代收集器、单线程
Client模式下使用
作为CMS的后备方案
5)Parallel Old收集器
Parallel Scavenge的老年代版本
多线程,标记-整理算法
6)CMS收集器
以最短停顿时间为目标
使用标记-清除算法
过程:
初始标记-stop the world
并发标记
重新标记-stop the world
并发清除
虽然有stop the world过程,但是用时很短。
用时最长的并发标记与并发清除,可以与用户线程一起工作。