垃圾收集的核心目标(重点)
这三个问题肯定要会答
- 哪些内存需要回收
- 什么时候回收
- 如何回收
哪些内存需要回收(重点)
- 程序计数器,虚拟机栈,本地方法栈随线程而生,随线程而灭不需要过多考虑内存回收
- Java堆和方法区作为共享区域具有显著的不确定性,其对象的分配和回收都是动态产生的。
什么时候回收(重点)
可达性分析算法 (这个必背,除了这里还有下一篇的详细分析要会)
如上图所示,object1~object4对GC Root都是可达的,说明不可被回收,object5和object6对GC Root节点不可达,说明其可以被回收。
术语:
- GCroot:根对象,也叫做起始节点集
- reference chain:引用链,从GCroot出发根据引用关系向下搜索,搜索过程走过的路径
在Java中,可作为GC Root的对象包括以下几种:(重点,而且要能举例)
引用分类
- 强引用:正常的引用赋值,"Object obj = new Object()",只要强引用在,垃圾收集器就永远不会回收掉被引用对象
- 软引用:在系统发生溢出异常前,才会把这些对象列入回收范围之中进行二次回收
- 弱引用:关联的对象只能生存到下一次垃圾收集发生为止,hashmap那里有相关知识点
- 虚引用:不用管,没啥用
如何回收(重点)
三个分代假说(了解)
- 弱分代假说:大多数对象都是朝生夕灭的
- 强分代假说:熬越多次垃圾收集过程的对象越难以消亡
- 跨代引用假说:跨代引用相对于同代引用来说仅是少数
记忆集(了解)
跨代引用的解决方案
假如只局限于新生代的收集,那么我们将错误的回收E;若想正确回收,那就需要对老年区同样做一次GC搜索,明显效率低下。(效率低下是基于跨代引用假说)
解决方案就是在新生代上使用一个全局的数据结构,称为记忆集。如果发现老年代的内存区域存在新生代的引用,那么将会将对象加入记忆集。垃圾回收时,记忆集里面的对象会加入GCroot,就避免了老年代的全遍历回收。
它需要在对象改变引用关系的时候维护记录数据的正确性,增加一些运行时开销,但比起收集时扫描整个老年代还是划算。
这三个必背
标记-清除算法:
- 标记阶段:先通过根节点,标记所有从根节点开始的对象,未被标记的为垃圾对象
- 清除阶段:清除所有未被标记的对象
缺点:
- 执行效率低,标记需要遍历一次堆,清除也要遍历一次堆
- 内存空间碎片化,标记清除后产生大量不连续的内存碎片
标记-复制算法:
- 标记阶段:先通过根节点,标记所有从根节点开始的可达对象,未被标记的为垃圾对象
- 复制阶段:将原有的内存空间分为两块,每次只使用一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未被使用的内存块中,然后清除正在使用的内存块中的所有对象。
缺点:
- 空间浪费一半
标记-整理算法:
- 标记阶段:先通过根节点,标记所有从根节点开始的可达对象,未被标记的为垃圾对象
- 整理阶段:将所有的存活对象压缩到内存的一个统一区域,之后清理边界外所有的空间
三种算法的比较:
- 效率: 复制 > 标记整理 > 标记清除
- 内存利用率: 标记整理 > 标记清除 > 复制
- 内存整齐度: 复制 = 标记整理 > 标记清除
总结
面试如果让你介绍垃圾回收算法就这么泛泛谈即可,具体深入见下篇文章
标签:标记,对象,清理,内存,回收,垃圾,JVM,引用 来源: https://www.cnblogs.com/KODGV-H/p/14310499.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。