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

Java虚拟机_Java虚拟机:GC算法和种类

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java虚拟机:GC算法和种类相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java虚拟机:GC算法和种类相关的知识,希望对你有一定的参考价值。




一、如何确定垃圾?

  在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中那些还“存活”着,哪些已经“死去”(即不可能再被任何途径使用的对象)了。


1. 引用计数法:



  •  在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关

联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。



  • 使用者有微软COM(Component Object Model)技术、使用ActionScript3的FlashPlayer、Python语言以及在游戏脚本领域得到许多应用的Squirrel;

  • 但在Java领域,至少主流的Java虚拟机里面都没有选用引用计算法来管理内存。

实现:

  1> 对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;

  2> 当引用失效时,引用计数器就减1;

  3> 只要对象A的引用计数器的值为0,则对象A就不可能再被使用。

缺点:



  • 引用和去引用伴随加法和减法,影响性能

  • 很难解决对象之间相互循环引用的问题。


2. 可达性分析:



  • 为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC  roots”对象作为起点搜索。如果在“GC  roots”和一个对象之间没有可达路径,则称该对象是不可达的。

  • 要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。

 


3. 四种引用类型:



  • 强引用:是指在程序代码中普通存在的引用赋值,即类似“Object obj = new Object()”这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。

  • 软引用:用来描述一些还有用,但非必须的对象。只被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK1.2版之后提供了SoftReference类来实现软引用。

  • 弱引用:也是用来描述那些非必须的对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2版之后提供了WeakReference类来实现弱引用。

  • 虚引用:也称为“幽灵引用”或者“幻影引用”,它是最弱的一种引用关系。虚引用完全不会对一个对象的生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象呗收集器回收时收到一个系统通知。在JDK1.2版之后提供了PhantomReference类来实现虚引用。


二、垃圾收集算法


1. 分代收集理论

  当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”(Generational Collection)的理论进行设计,分代收集名为理论,实质是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上:

    1) 弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。

    2) 强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡。

  这两个分代假说共同奠定了多款常用的垃圾收集器的一致的设计原则:收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄(对象熬过垃圾收集过程的次数)分配到不同的区域之中存储。设计者一般至少会把Java堆划分为新生代(Young Generation)和老年代(Old Generation)两个区域。顾名思义,在新生代中,每次垃圾收集时都发现有大批对象死去,而每次回收后存活的少量对象,将会逐步晋升到老年代中存放。

  在Java堆划分出不同的区域之后,垃圾收集器才可以每次只回收其中某一个或者某些部分的区域——因而才有了“Minor GC”、“Major GC”、“Full GC”这样的回收类型 的划分;也才能针对不同的区域安排与里面存储对象存亡特征相匹配的垃圾收集算法——因而发展出了“标记——清除算法”、“标记——整理算法”等针对性的垃圾收集算法。


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



  • 标记-清除算法是现代垃圾回收算法的思想基础。

  • 标记-清除算法将垃圾回收分为两个阶段:标记和清除。

  • 实现:

    • 在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。

    • 在清除阶段,清除所有未被标记的对象。



具体过程如下图所示:

 

缺点:

  1)执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低;

  2) 会产生大量不连续的内存碎片。可能会导致在需要分配较大对象时,无法找到足够的连续内存,而不得不提前进行另一次的垃圾收集动作。


3. 标记-复制算法



  • 与标记-清除算法相比,复制算法是一种相对高效的回收方法

  • 不适用于存活对象较多的场合 如老年代

  • 将原有的内存空间分为两块,每次只使用其中一块

    • 在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,

    • 之后,清除正在使用的内存块中的所有对象,

    • 最后,交换两个内存的角色,完成垃圾回收



具体过程如下图所示:

 

缺点:



  • 空间浪费,内存缩小为原来的一半。

 


4. 标记-整理算法



  • 标记-整理算法适合用于存活对象较多的场合,如老年代。

  • 它在标记-清除算法的基础上做了一些优化。

    • 和标记-清除算法一样,标记-压缩算法也首先需要从根节点开始,对所有可达对象做一次标记。

    • 但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端。

    • 最后,清理边界外所有的空间。



具体过程如下图所示:

 


三、Stop-The-World



  • Java中一种全局暂停的现象

  • 全局停顿,所有Java代码停止,native代码可以执行,但不能和JVM交互

  • 多半由于GC引起


    •   Dump线程

    •   死锁检查

    •   堆Dump


GC时为什么会有全局停顿?
  类比在聚会时打扫房间,聚会时很乱,又有新的垃圾产生,房间永远打扫不干净,只有让大家停止活动了,才能将房间打扫干净。

危害:



  • 长时间服务停止,没有响应

  • 遇到HA系统,可能引起主备切换,严重危害生产环境。




推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 提升Python编程效率的十点建议
    本文介绍了提升Python编程效率的十点建议,包括不使用分号、选择合适的代码编辑器、遵循Python代码规范等。这些建议可以帮助开发者节省时间,提高编程效率。同时,还提供了相关参考链接供读者深入学习。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • MySQL8.0设置远程访问权限的方法
    这篇文章主要介绍了MySQL8.0设置远程访问权限的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着 ... [详细]
  • Android NDK开发的一点尝试
    写在前面笔者是一个“原始”的C++开发者,对Java编程虽说不上抵触但也没有C++那么顺手。而且,作为一个游戏引擎,不管是在什么地方,效率总是第一位的,尤其是在移动平台这样资源吃紧 ... [详细]
  • 2021 年 10 月 TIOBE 指数榜:Python 超越 C 语言成 20 多年来的新霸主
    TIOBE更新了2021年10月份编程语言指数排行榜。榜单中共对100种编程语言进行了评级排名,其中Python成为“20多年来的新语言霸主”,以11. ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 现在不少人开始关注并学习Flex了(至少比以前多了),但是现在关于Flex的资料并不多,国内的资料就更少了,而 ... [详细]
author-avatar
吴姿云68153
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有