判断对象是否可被回收:
1.引用计数法:给对象添加一个引用计数器,每被引用一次,计数器+1,引用失效时,计数器-1;
优点:实现简单,判断效率高;
缺点:难以解决对象直接相互循环引用问题(ObjA和ObjB互相引用,则引用计数永远不为0)
2.可达性分析算法:以GC Roots为起点向下搜索,搜索过的路径为引用链。当一个对象和GC Roots之间没有引用链的话,则对象可以被回收。该算法是主流商业语言的判断对象存活的实现。
GC Roots:根引用集合,一组必须活跃的应用。具体见R大的回答 https://www.zhihu.com/question/53613423/answer/135743258
GC算法:
1.标记-清除算法:1.标记需要回收的对象;2.回收所有被标记的对象
缺点:1.标记和清除效率都不高;2.会产生大量的内存碎片
2.复制算法:1.把内存划为大小相等的两块,只使用其中的一块;2.复制已使用内存对象到另一块上面(移动堆顶指针,按顺序分配内存),清理原来块上内存
优点:实现简单,运行高效;
缺点:对象存活率较高时需要进行较多复制操作,降低效率;
可用内存仅有总内存的一半(主要缺陷)
解决方案:分配担保,因为新生代中98%的对象是朝生夕死的,所以将新生代分为一块Eden(80%)和两块Survivor(10%*2),每次使用Eden和其中一块Survivor,回收时,将所有存活对象移到另一块Survivor,清理到之前使用的Eden和Survivor。这样新生代内90%的内存可用。当Survivor空间不足时,需要依赖老年代进行分配担保,对象直接进入老年代。
PS:GC时,大对象(大于-XX:PretenureSizeThreshold参数)会直接进入老年代。
3.标记-整理算法:标记-清除算法后,让所有存活的对象都向一端移动,然后清理掉边界外的内存
4.分代收集算法:新生代采用复制算法,老年代采用标记-清除&标记-整理算法。因为老年代没有额外空间进行分配担保,所以不能使用复制算法。