1.如何判断对象可以回收
1.1引用计数法(python使用)
每一个对象都会有,对应的应用值,记录该对象被应用的数量。
1.2可达性分析算法(java虚拟机使用)
扫描堆中的对象,看是否能够沿着GC Root对象为起点的引用链找到该对象,找不到,表示可以回收。
什么对象能作为 GC Root
Memory Analyzer java堆分析工具,能查看堆快照的GC Root对象。
1、核心类
2、操作系统应用的java对象
3、活动线程中的对象
4、带锁的对象
1.3 四种引用
1、强引用
平常使用的都是强应用。
2、软引用
通过强引用间接引用。进行垃圾回收,并且内存不够时,进行回收。
当软引用的对象被回收后,软引用会进入到一个引用队列中,等待回收引用所占用的内存。
3、弱引用
发送垃圾回收,就会进行回收。
当弱引用的对象被回收后,弱引用会进入到一个引用队列中,等待回收引用所占用的内存。
4、虚引用
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
主要是为了
ByteBuffer开辟一个直接内存时会创建虚引用,为的是在ByteBuffer对象被垃圾回收后,能释放直接内存。
5、终结器引用(不推荐的引用)
重写对象 finallize() 方法(好像不一定)。
当没有强引用引用当前对象了,并且进行垃圾回收,就会将终结器引用放入到引用队列中。
此时对象还未被回收。
在由一个优先级很低的(finallizeHandler)线程,来查看队列中的引用,调用对象的finallize()方法,在下次垃圾回收时就会被回收。
不推荐使用,因为线程优先级低,而且回收流程繁琐
总结
2.垃圾回收算法
2.1标记清除算法
1、将没有被GC Root对象引用的对象进行标记。
2、将内存对应的内存清除。
优点:速度快
缺点:容易产生内存碎片,会导致较大的对象,无法存入。
2.2 标记整理
与标记清除前面的步骤相同:
1、将没有被GC Root对象引用的对象进行标记。
2、将内存对应的内存清除。
3、整理内存。
缺点:因为要整理对象内存地址,所以速度比较慢
2.3 复制
将内存划分成两个区域,FROM与TO。
1、在FROM区中,标记不被使用的内存
2、将FROM中依旧存在的对象,赋值到TO区中
3、在将FROM与TO区交换
缺点:占用双倍的内存空间
总结
JVM中,三种算法都会根据在不同的情况下使用。
3.分代的垃圾回收机制
新生代相较于老年代,会比较频繁地进行垃圾回收
回收基本流程
1、产生新对象后,对象会进入到伊甸园区。
2、当伊甸园空间不足时。
先,进行Minor GC,采用复制算法。
将,存活的对象复制到辛存区TO中,并且辛存的对象寿命加一。
最后,交换FROM与TO(交换引用)。
就可以继续正常的使用了
3、当伊甸园又空间不足时。
步骤与“2”一样。
但是当一个对象寿命达到15(默认是15),就晋升到老年代当中去。
4、当新生代与老年代都空间不足时就会进行,Full GC来将新生代与老年代都进行清理。
总结
Eden(伊甸园)区、Survivor(辛存)区、Old(老年代)区
大对象:对象内存大小超过新生代Eden区时,如果老年代足够内存存放,就会直接晋升到老年代。
如果老年代空间不够,就会抛出内存溢出异常。
4.垃圾回收器
1.串行
- 单线程 (进行垃圾回收时其他线程都会停止)
- 堆内存较小,适合个人电脑
2.吞吐量优先
- 多线程
- 堆内存较大,多核cpu
- 让单位时间内,STW的时间最短(频率较低,执行时间较长)
3.响应时间优先(复杂)
- 多线程
- 堆内存较大,多核cpu
- 尽可能让STW的单次时间最短(频率较高,执行时间较短)