1、对象是死是活
- 引用计数算法
- 思路:给对象添加一个引用计数器,有一个地方引用就+1,引用失效就-1,当计数器为0时对象就不能再被使用
- Java没有选用引用计数算法来管理内存,最主要原因是它很难解决对象之间相互循环引用的问题
- 根搜索算法
- 思路:通过一系列名为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(从GC Roots到这个对象不可达)时,则证明此对象是不可用的
- java使用
- 任何一个对象的**finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收它的finalize()**方法不会被再次执行。
- finalize()能做的所有工作,使用try-finally或者其他方式都可以做得更好、更及时
2、垃圾收集算法
- 标记-清除算法
- 思路:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象
- 两个问题:效率不高;空间问题,会产生大量不连续的内存碎片
- 复制算法
- 思路:把可用的内存按容量分为大小相等的两块,每次只使用其中一块,当一块使用完了,就将还存活的对象复制到另一块上,然后把已经使用过的内存空间一次清理掉
- 商业虚拟机用这种算法回收新生代,只不过是内存划分为一块较大的Eden空间和两块较小的Survivor空间,每次就使用Eden和一块Survivor,回收时把存活的对象复制到另一块Survivor上,然后清理Eden和使用过的Survivor
- 标记-整理算法
- 思路:标记同上,然后让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存
- 分代收集算法
- 根据对象的存活周期不同将内存划分为几块,一般把Java堆划分为新生代和老年代,新生代用复制算法,老年代用标记-清理或标记-整理算法
3、内存分配与回收策略
- 大对象直接进入老年代
- 大对象指需要大量连续内存空间的Java对象,最典型的是很长的字符串及数组
- PretenureSizeThreshold这个参数只对Serial和ParNew两款收集器有效
- 长期存活的对象将进入老年代
- 动态对象年龄判定
- 如果在Survivor空间中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象直接进入老年代