热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JVM-3.垃圾判定,回收算法

垃圾判定,回收算法垃圾判定垃圾回收的重要环节是判定哪些对象需要回收,重要的回收算法有:引用计数算法(COM,ActionScript,Python)可达性分析算法(Ja

垃圾判定, 回收算法

垃圾判定

垃圾回收的重要环节是判定哪些对象需要回收, 重要的回收算法有:

  1. 引用计数算法(COM, ActionScript, Python)
  2. 可达性分析算法(Java, C#, Lisp 采用)

引用计数算法

什么是引用计数算法?

每个对象中有一个引用计数器:

  • 每当有一个地方引用它, 计数器的值就会加一
  • 每当有一个引用失效, 计数器的值就会减一

优点和不足

引用计数的优点是:

  1. 实现简单
  2. 效率高

缺点是:

难以解决循环引用的问题.

可达性分析算法

通过 GC Roots 的对象作为起点, 从这些节点开始往下搜索, 搜索经过的路径称为 "引用链".

当一个对象和 GC Roots 之间没有"引用链"可以连接, 则 GC Roots 到此对象不可达, 此对象需要回收.

那么作为顶点的 GC Roots 包括哪些呢?

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象
  2. 本地方法栈中引用的对象
  3. 方法区中, 静态变量引用的对象
  4. 方法区中常量引用的对象

引用

JDK 1.2 之前, Java 引用只有一种:

reference 类型的数据中存储的数值代表的是另外一块内存的起始地址

JDK 1.2 之后, Java 拓展出 4 种引用:

  • 强引用(Strong), 普通引用对象, 如 Object obj = new Object(). 永远不会被回收掉的引用对象.

  • 软引用(Soft), 非必须对象, 内存逸出异常抛出之前回收
  • 弱引用(Weak), 比软引用弱, 非必须对象, 无论内存是否足够都会被回收
  • 虚引用(Phantom), 最弱的引用关系, 无法通过引用获取实例

方法区的回收

方法区回收主要回收以下两类:

  1. 废弃常量, 回收条件: 系统中没有任何一个对象引用到此常量
  2. 无用的类, 回收条件:
  • 该类所有实例都已经被回收
  • 加载该类的 ClassLoader 已经被回收
  • 该类的对应的 java.lang.Class 没有任何地方被引用.

回收算法

标记-清除 (Mark-Sweep) 算法

算法分 "标记" 和 "清除" 两个阶段, 首先标记出所有需要回收的对象, 在标记完成后统一回收所有被标记的对象.

优点是简单, 不足之处是:

  1. 效率比较低
  2. 空间不连续, 原地清除, 碎片多, 若分配大对象时, 可能会因为空间不足而触发一次 GC.

常用在老年代.

复制 (Copying) 算法

此算法将内存分成两块, 当一块内存用完之后, 就将 __还存活着的对象__复制到另外一块上面.

优点是: 效率高
缺点是: 内存利用不充分

常用在新生代.

HotSpot 中将新生代划分为 Eden 和两块 Survivor 区域, 默认 Eden 与一块 Survivor 的比例是 8:1.

每次 Eden 和 一块 Survivor(A) 负责分配, 另一块 Survivor(B) 为替补.

  • 当空间需要回收且 B 大小足够容纳 Eden+A 中的存活对象时, 会将 Eden 和 A 中的对象复制到 Survivor 中, 然后 Eden 和 复制后的 Survivor(B) 一起作为负责分配的空间, A 成为替补.

  • 当空间需要回收且 B 大小不够容纳 Eden+A 中的存活对象时, 会将 Eden+A 中的对象复制到 老年代.

标记-整理 (Mark-Compact) 算法

算法分 "标记" 和 "整理" 两个阶段, 首先标记出所有需要回收的对象, 然后让所有存活的对象都向一端移动.

它解决了 标记-清除 算法中, 碎片过多的问题.

安全点和安全区域

为什么 GC 时需要卡顿(__Stop the world)?

因为 GC 需要将某一刻全局(常量和静态变量)和执行上下文中(栈)的中的所有 GC Roots 找到并枚举, 进行可达性分析.

现在主流的 GC 都使用 OopMap 来保存每个对象什么偏移量存什么数据, 以及栈和寄存器中哪些位置是引用. 这样 GC 就不用每次在停顿后通过遍历来得知 GC Roots 了.

安全点 (Safepoint)

OopMap 记录的信息不需要记录太频繁, 否则占额外空间太多也运行时效率; 也不能太长时间不记录, 否则影响 GC 效率.

OopMap 记录的位置叫 安全点, 位置的选取标准为: 让程序长时间执行.

那么如何让线程在安全点停下来呢? 有两种方式:

  1. 抢先式中断, JVM 强制中断全部线程, 检查他们是否在安全点上, 若有的线程不在安全点, 则, 让他们运行直到在安全点.
  2. 主动式中断, JVM 需要中断线程时, 就设置一个全局的中断标志, 让线程轮询这个中断标志.

安全区域 (Safe Region)

安全区域是扩展了的安全点, 代表此区域中, 引用关系不会发生改变, GC 总是安全的. 它主要解决以下问题:

GC 时, 并不是所有线程都是在 "活动" 状态的, 有的时候, 线程无法轮询中断标志, 因为他们正在被挂起(Sleep 或者 Blocked).

对于 Sleep 和 Blocked 而言, 本地变量栈是线程私有的, 栈上对象的引用当然不会变, 所以 Sleep 和 Block 属于安全区域代码.

当线程执行到安全代码时,

  1. 线程先标明已经进入 安全区域 区
  2. 若 JVM 此时发起 GC, 这些线程就会被忽略
  3. 当线程离开 安全区域 时, 会检查系统是否完成了根节点枚举
  4. 若完成, 线程继续执行, 否则, 它会等待直到收到可以离开 安全区域 的信号

推荐阅读
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 导读:很多朋友问到关于php前端脚本语言有哪些的相关问题,本文编程笔记就来为大家做个详细解答,供大家参考,希望对大家有所帮助!一起来看看吧!本文目录一览: ... [详细]
  • Final关键字的含义及用法详解
    本文详细介绍了Java中final关键字的含义和用法。final关键字可以修饰非抽象类、非抽象类成员方法和变量。final类不能被继承,final类中的方法默认是final的。final方法不能被子类的方法覆盖,但可以被继承。final成员变量表示常量,只能被赋值一次,赋值后值不再改变。文章还讨论了final类和final方法的应用场景,以及使用final方法的两个原因:锁定方法防止修改和提高执行效率。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
author-avatar
liujiayan0529_584
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有