摘要

Java程序在运行过程中会产生大量的对象,但是内存大小是有限的,如果光用而不释放,那内存迟早被耗尽。如C、C++程序,需要程序员手动释放内存,Java则不需要,是由垃圾回收器去自动回收。

垃圾回收器回收内存至少需要做两件事情:标记垃圾、回收垃圾。于是诞生了很多算法及垃圾回收器。

垃圾判断算法

即判断JVM中的所有对象,哪些对象是存活的,哪些对象可回收的算法。

引用计数算法

在对象中添加一个属性用于标记对象被引用的次数,每多一个其他对象引用,计数+1,当引用失效时,计数-1,如果计数=0,表示没有其他对象引用,就可以被回收。

这个算法无法解决循环依赖的问题。

可达性分析算法

通过一系列被称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系链向下搜索,如果某个对象无法被搜索到,则说明该对象无引用执行,可回收。相反,则对象处于存活状态,不可回收。

JVM中的实现是找到存活对象,未打标记的就是无用对象,GC时会回收。

哪些对象可以作为GC Root呢:

  • 所有Java线程当前活跃的栈帧里指向GC堆里的对象的引用;换句话说,当前所有正在被调用的方法的引用类型的参数/局部变量/临时值。
  • VM的一些静态数据结构里指向GC堆里的对象的引用,例如说HotSpot VM里的Universe里有很多这样的引用。
  • JNI handles,包括global handles和local handles
  • (看情况)所有当前被加载的Java类
  • (看情况)Java类的引用类型静态变量
  • (看情况)Java类的运行时常量池里的引用类型常量(String或Class类型)
  • (看情况)String常量池(StringTable)里的引用

垃圾回收算法

1、标记-清除算法

概念:

顾名思义,标记-清除算法分为两个阶段,标记(mark)和清除(sweep)。

标记:遍历所有的GC Roots,然后将所有的GC Roots可达的对象标记为存活的对象。

清除:清除的过程将遍历所有堆中的对象,将没有标记的对象全部清除。

图解:

对上图中的黄色部分进行垃圾回收,回收后的截图如下所示:

从图中可知,进行标记清理后,可用内存增加,但是清除垃圾后的内存地址不连接,出现垃圾碎片。

缺点:

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

2、内存空间碎片化的问题,标记、清除后会产生大量的不连续内存碎片,空间碎片太可能会导致当以后需要分配大对象时无法找到足够的连续内存二不得不提前触发另一次垃圾收集动作。

2、标记-复制算法

概念:

复制算法将内存分为两个区间,这两个区间是动态的,在任意一个时间点,所有分配的对象内存只能在其中一个区间(活动区间),另外一个区间就是空闲区间。
当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程。GC线程会将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址一次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。这个时候空闲内存已经变成了活动区间,垃圾对象全部在原来的活动区间,清理掉垃圾对象,原活动区间就变成了空闲区间。

这种方式内存的代价太高,每次基本上都要浪费一半的内存。于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存划分为8:1:1三部分,较大那份内存是Eden区,其余是两块较小的内存区叫Survior区。每次都会优先使用Eden区,若Eden区满,就将对象复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多,以至于Survivor不够时,会将这些对象通过分配担保机制复制到老年代中。(java堆又分为新生代和老年代)。

图解:

优点:

1、很好地解决了“标记-清除”算法,内存布局混乱的缺点。

缺点:
1、浪费一半的内存。

2、假设对象存活率为100%,那么“标记-复制”算法的GC过程就是重复的把对象复制一遍,而且将所有的引用地址重置一遍。可以预见的复制所消耗的时间随着对象存活率达到一定程度将会变成灾难。所以“标记-复制”算法使用的场景是可以忍受只是用50%内存,对象存活率非常低

3、标记-整理算法

概念:

标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

图解:

优点:

1、弥补了“标记-清除”算法,内存区域分散的缺点
2、弥补了“标记-复制”算法内存减半的代价

缺点:

1、效率不高,对于“标记-清除”而言多了整理工作。

4、分代收集算法

当前商业虚拟机的垃圾收集都采用分代收集。此算法没啥新鲜的,就是将上述三种算法整合了一下。具体如下:
根据各个年代的特点采取最适当的收集算法

1、在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法。只需要付出少量存活对象的复制成本就可以完成收集。
2、老年代中因为对象存活率高、没有额外空间对他进行分配担保,就必须用标记-清除或者标记-整理。

测试案例

以下测试采用的是Serial加Serial Old收集器组合。

查看当前jdk默认额收集器使用以下语句。

java -XX:+PrintCommandLineFlags -version

1、对象优先在Eden分配

测试代码

2、大对象直接进入老年代

3、长期存活的对象将进入老年代

4、动态年龄判断

5、空间分配担保

 

JVM 垃圾收集算法 标记-清楚、标记-复制、标记-整理的更多相关文章

  1. JVM垃圾收集算法(标记-清除、复制、标记-整理)

     [JVM垃圾收集算法] 1)标记-清除算法: 标记阶段:先通过根节点,标记所有从根节点开始的对象,未被标记的为垃圾对象(错了吧?) 清除阶段:清除所有未被标记的对象 2)复制算法: 将原有的内存空间 ...

  2. JVM垃圾收集算法之标记算法

    前言 总所周知,jvm的垃圾收集算法一般包括标记.清除.整理三个阶段,最近在看了有关于垃圾收集的标记算法,记录一下自己的理解. 垃圾收集中标记算法有两种:一种是引用计数法,一种是根搜索算法. 引用记数 ...

  3. JVM垃圾收集算法

    JVM垃圾收集 1. 判断对象是否存活 引用计数算法 对象添加一个引用计数器,每个地方引用它,计数器值加+1:当引用失效,计算器值减1:任何时刻计数器为0的对象不可能被使用.引用计数算法实现简单,高效 ...

  4. JVM垃圾收集算法之清除算法

    最近看了一些大佬的博文,文中提到说:学习知识不能一味的死学滥学,在学之前要明白为什么要学这个知识,在实际的应用中怎么运用这个知识.我觉得说的很对,很多时候我学习确实是了解了这是什么原理,但是要说到实际 ...

  5. JVM——垃圾收集算法及垃圾回收器

    一.垃圾回收算法 1.标记-清除算法 1)工作流程 算法分为"标记"和"清除"阶段:首先标记出所有需要回收的对象(标记阶段),在标记完成后统一回收所有被标记的对 ...

  6. JVM——垃圾收集算法

    1.标记-清除算法 最基础的收集算法,如其名,算法为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象. 两个不足: 1)效率问题,标记和清除两个过程的效率 ...

  7. 【004】【JVM——垃圾收集算法】

     Java虚拟机学习总结文件夹 垃圾收集算法 垃圾收集算法的实现涉及大量的程序细节,并且各个平台的虚拟机操作内存的方法又各不同样,介绍几种垃圾收集算法的思想及其发展过程. 标记-清除算法 垃圾收集 ...

  8. [jvm] -- 垃圾收集算法篇

    垃圾收集算法 标记-清除算法 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象. 缺点: 效率问题: 空间问题(标记清除后会产生大量不连续的碎片) 复制算法 它可以将内存分为大小相同 ...

  9. JVM垃圾收集算法——分代收集算法

    分代收集算法(Generational Collection): 当前商业虚拟机的垃圾收集都采用"分代收集算法". 这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分 ...

随机推荐

  1. Java和Scala容器转换

    参考:https://blog.csdn.net/dymkkj/article/details/77921573 Java和Scala互操作的一个重要的内容就是容器的转换,容器是一个语言的数据结构,表 ...

  2. Servlet容器启动过程

    参考:https://blog.csdn.net/fredaq/article/details/9366043 一.概念 所谓Servlet容器其实说白了是符合Servlet规范的Java web容器 ...

  3. zabbix配置钉钉机器人告警

    目录 zabbix配置钉钉机器人告警 1. 在钉钉中创建群聊,在群里面添加自定义机器人 2. 配置钉钉告警脚本 3. 配置脚本告警 3.1 创建媒介 3.2 为用户添加对应媒介 3.3 创建动作 4. ...

  4. Java自学-JDBC 数据库连接池

    数据库连接池 与线程池类似的,数据库也有一个数据库连接池. 不过他们的实现思路是不一样的. 本章节讲解了自定义数据库连接池类:ConnectionPool,虽然不是很完善和健壮,但是足以帮助大家理解C ...

  5. WPF桌面程序在请求接口时如何防止被常用的抓包软件Fiddler抓包

    问题:在我开发了一个WPF桌面应用程序的时候,由于涉及到登录等等操作通过Fiddler可以很直观的看到账号密码.首先问题有两点:1.数据提交的时候对于密码等重要的数据没有进行加密操作.2.没有防止抓包 ...

  6. Spring Cloud 之分布式配置基础应用

    分布式配置基础应用 配置中心服务 spring-config-server pom.xml <?xml version="1.0" encoding="UTF-8& ...

  7. Windows下制作软件安装包

    一.下载 首先,下载SetupFactory9.0.3.0Trial(下载链接:https://www.haolizi.net/example/view_65380.html) 下载好会有一个压缩包 ...

  8. C#LeetCode刷题之#160-相交链表(Intersection of Two Linked Lists)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3824 访问. 编写一个程序,找到两个单链表相交的起始节点. 例如 ...

  9. java如何实现发送邮箱

    package cn.buy.util; import java.security.GeneralSecurityException; import java.util.Properties; imp ...

  10. 【期外】(二)还是N皇后动画演示

    题目:n皇后题目 题解:n皇后题解 演示: