一,了解GC所关注的问题
- 什么时候回收
- 哪些内存需要回收
- 如何回收
注: GC所关注的主要区域 是 Java堆 和 方法区,Java虚拟机规范中对于垃圾收集器如何实现没有任何规定
二,什么时候回收?
GC经常发生的区域是堆区,堆区还可以细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。
- 对象优先在Eden中分配,当Eden中没有足够空间时,虚拟机将发生一次Minor GC,因为Java大多数对象都是朝生夕灭,所以Minor GC非常频繁,而且速度也很快;
- Full GC,发生在老年代的GC,当老年代没有足够的空间时即发生Full GC,发生Full GC一般都会有一次Minor GC。大对象直接进入老年代,如很长的字符串数组,虚拟机提供一个-XX:PretenureSizeThreadhold参数,令大于这个参数值的对象直接在老年代中分配,避免在Eden区和两个Survivor区发生大量的内存拷贝;
- 发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则进行一次Full GC,如果小于,则查看HandlePromotionFailure设置是否允许担保失败,如果允许,那只会进行一次Minor GC,如果不允许,则改为进行一次Full GC。
三, 判断对象是否已死
- 引用计数算法
- 内容:每当有一个地方引用它时,计数器加一,当引用失效时,计数器减一;任何时刻计数器为0的对象是不能再被使用的。
- 优点:实现简单, 效率高
- 缺点:难解决对象相互循环引用的问题
- 可达性分析算法
- 内容:当一个对象到GC roots 没有任何引用链相连,此对象不可用
- GC roots 包含 对象 1. 虚拟机栈中引用的对象 2.方法区中类静态属性引用的对象 3. 方法区中常量引用的对象 4.本地方法栈中 JNI (native 方法)中引用的对象 (为什么呢 ????)
四. 垃圾回收算法
- 标记-清除算法
- 算法:标记所有需要回收的对象,在标记完成后统一回收所有被标记对象。
- 缺点:1. 标记和清除的效率不高 2.清除后会产生大量不连续的内存碎片
- 复制算法
- 算法:将可用内存分成大小相等的两块,每次只使用其中的一块,当这块用完了,就将还存活的对象复制到另一块上,然后清理掉一整块用过的内存空间
- 优点:实现简单,运行效率高
- 缺点:内存缩小为原来的一半,存活率较高时就需要较多的复制操作,效率降低
- 标记整理算法
- 算法:标记所有需要回收的对象,将所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
- 解决了 标记清除算法 产生大量不连续的内存碎片问题
- 分代收集算法
- 算法:Java 堆 分为 新生代 和 老年代,根据各个年代的特点采用最适合的收集算法。新生代 有大批对象死去,选用复制算法;老年代 对象存活率高,没有额外空间对它进行分配担保,采用 标记清理,标记整理算法回收
问题
- 是怎么标记要回收的对象
如果对象在进行可达性分析后发现没有与 GC Roots 相连接的引用链,那么它将会被第一次标记并且进行一次筛选,筛选条件(对象是否有必要执行finalize()),当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过都视为“没有必要执行”,如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在F-Quene 的队列之中,稍后GC将对队列上的对象进行第二次小规模标记,如果对象在finalize()中成功拯救自己--只要重新与引用链上任何一个对象建立关联即可,那么第二次标记时它将被移除“即将回收”的集合,如果没有逃脱就被标记为要回收的对象 - GC roots 对象为什么是定义那些
待解决