Java 垃圾收集器

news2024/10/9 0:52:11

堆内存示意图

垃圾收集算法

1.标记-清除算法

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

缺点:

  1. 执行效率不稳定,若堆中有大量对象要被回收,这是必须进行大量标记和清除动作,执行效率随对象增长而降低。
  2. 内存空间的碎片化问题,标记、清除后会产生大量不连续的碎片,当程序需要分配大对象时无法找到足够的连续内存而不得不提取触发垃圾收集。

2.标记-复制算法

多数对象是可回收的情况下,算法需要复制占少数的存活对象;每次针对半个区域进行内存回收,分配内存时不用考虑内存碎片情况,只要移动堆顶指针,按顺序分配即可。实现简单、运行高效。

缺点:

  1. 代价是将可用内存缩小为原来的一半,浪费内存空间。

3.标记-整理算法

标记过程与标记清除算法一样,后续步骤不一样。后续步骤是将存货对象向一端移动,然后直接清除掉端边界以外的内存。

优点:

  1. 相比标记清除算法,没有碎化的内存
  2. 相比标记复制算法,没有内存减半的消耗

缺点:

  1. 整理活动对象时,因对象位置变动,需要调整虚拟机栈中的引用地址
  2. 整理活动对象时,需要全程暂停用户线程,STW
  3. 效率相比于标记复制算法低一些

四种引用

1.强引用

最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。

当一个对象被强引用变量引用时,它处于“活着”状态,它不可能被回收的。

2.软引用

SoftReference,对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。

/**
 * java -Xms10m -Xmx10m SoftReferenceTest 
 */
public class SoftReferenceTest {

    static class HeapObject {
        byte[] bs = new byte[1024 * 1024];
    }

    public static void main(String[] args) {
        SoftReference<HeapObject> softReference = new SoftReference<>(new HeapObject());

        List<HeapObject> list = new ArrayList<>();

        while (true) {
            if (softReference.get() != null) {
                list.add(new HeapObject());
                System.out.println("list.add");
            } else {
                System.out.println("---------软引用已被回收---------");
                break;
            }
            System.gc();
        }
    }
}

3.弱引用

WeakReference,弱引用也是用来描述非必需对象的,它的强度比软引用更弱一些。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。

/**
 * jdk 1.8
 */
public class WeakReferenceTest {
    static class TestObject{

    }

    public static void main(String[] args) throws InterruptedException {
        WeakReference<TestObject> weakReference=new WeakReference<>(new TestObject());

        System.out.println(weakReference.get() == null);//false

        System.gc();
        TimeUnit.SECONDS.sleep(1);//暂停一秒钟

        System.out.println(weakReference.get() == null);//true
    }
}

Tips:软引用、弱引用都非常适合来保存那些可有可无的缓存数据。如果这么做,当系统内存不足时,这些缓存数据会被回收,不会导致内存溢出。而当内存资源充足时,这些缓存数据又可以存在相当长的时间,从而起到加速系统的作用。

4.虚引用

PhantomReference,最弱的一种引用关系,随时都有可能被垃圾回收器回收。

虚引用必须和引用队列(ReferenceQueue)联合使用,主要作用是跟踪对象被垃圾回收的状态。

JDK7/8后HotSpot虚拟机所有收集器

1.Serial收集器

新生代收集器

串行

单线程收集器,只用一个线程完成垃圾收集,且收集时必须暂停工作线程。

使用标记-复制算法。

  1. -XX:+UseSerialGC 指定年轻代和老年代都使用串行回收器,这是client模式下的默认选项

2.ParNew收集器

新生代收集器

串行

多线程收集,Serial收集器的多线程版本,GC时需要暂停工作线程

使用标记-复制算法

  1. -XX:+UseConcMarkSweepGC 指定使用CMS后,会默认使用ParNew作为新生代收集器;
  2. -XX:+UseParNewGC 强制指定使用ParNew;
  3. -XX:ParallelGCThreads 指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同;

3.Parallel Scavenge收集器

新生代收集器

并行

多线程收集,GC时需要暂停工作线程

高吞吐量为目标

标记-复制算法

虚拟机运行在Server模式下的默认垃圾收集器,适合那种交互少、运算多的场景.例如,那些执行批量处理、订单处理、工资支付、科学计算的应用程序.

  1. -XX:+MaxGCPauseMillis 控制最大垃圾收集停顿时间,大于0的毫秒数;这个参数设置的越小,停顿时间可能会缩短,但也会导致吞吐量下降,导致垃圾收集发生得更频繁。
  2. -XX:GCTimeRatio 设置垃圾收集时间占总时间的比率,0<n<100的整数,就相当于设置吞吐量的大小。
  3. -XX:+UseAdptiveSizePolicy 开启这个参数后,就不用手工指定一些细节参数,如: 1)新生代的大小(-Xmn);2)Eden与Survivor区的比例(-XX:SurvivorRation);3)晋升老年代的对象年龄(-XX:PretenureSizeThreshold)。(JVM会根据当前系统运行情况收集性能监控信息,动态调整这些参数,以提供最合适的停顿时间或最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC Ergonomiscs)

Parallel Scavenge收集器无法与CMS收集器配合使用,所以在JDK 1.6推出Parallel Old之前,如果新生代选择Parallel Scavenge收集器,老年代只有Serial Old收集器能与之配合使用。

CMS等收集器的关注点是尽可能地缩短STW停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。

4.Serial Old收集器

Serial 收集器在新生代和老年代都有对应的版本,除了算法不同,两个版本没有其他的差异

老年代收集器

串行

单线程收集器,垃圾收集时必须暂停工作线程

标记-整理算法

Client模式:默认使用Serial Old 收集器。

Server模式:在JDK1.5以及之前的版本中,与Parallel Scavenge收集器配合使用;最为CMS收集器的后备预案,在并发收集发生“Concurrent Mode Failure”时使用。

5.Parallel Old 收集器

Parallel Old是Parallel Scavenge 的老年版本,除了算法不同,两个版本没有其他差异

老年代收集器

并行

多线程收集器,GC时需要暂停工作线程

高吞吐量为目标

标记-整理算法

在注重吞吐量及CPU资源敏感的场合,可以优先考虑 Parallel Scavenge + Parallel Old收集器组合。

JDK1.6及之后来代替Serial Old收集器,特别是在 Server模式和多CPU情况下。

  1. -XX:UseParallel Old:指定使用Parallel Old收集器。

6.CMS(Concurrent Mark Sweep)收集器

CMS是HotSpot在JDK5推出的第一款真正意义上的并发(Concurrent)收集器,让垃圾收集线程与用户线程(基本上)同时工作。

老年代收集器

并发

多线程,收集过程基本不需要暂停用户线程

标记-清除算法

以最短停顿时间为目标

适用于用户较多的场景,应用集中在互联网或B/S系统的服务器上。这类服务注重响应速度,希望停顿时间最短,以给用户带来极好的体验。

CMS GC 过程的步骤

初始标记

  1. 单线程执行;
  2. 需要STW;
  3. 仅把GC Roots的直接关联的对象给标记下(对象量较小),速度非常快

并发标记

  1. 从GC Roots的直接关联对象开始遍历整个对象图进行标记的过程
  2. 虽然处理时间长,但不需要STW
  3. 不能保证标记出所有的存货对象

重新标记

  1. 并发标记过程中,可能会产生新的垃圾,所有需要重新标记
  2. 此时需要STW,停顿时间笔初始标记稍长,但远比并发标记短。

并发清除

  1. 并发清除标记的垃圾
  2. 不会STW

参数

  1. -XX:+UseConcMarkSweepGC:使用CMS收集器
  2. -XX:+ UseCMSCompactAtFullCollection:Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
  3. -XX:+CMSFullGCsBeforeCompaction:设置进行几次Full GC后,进行一次碎片整理
  4. -XX:ParallelCMSThreads:设定CMS的线程数量(一般情况约等于可用CPU数量)

缺点

1.对CPU资源敏感

虽然不会暂停用户线程,但因占用一部分CPU资源,会导致应用程序变慢、总吞吐量降低。

CMS的默认收集线程数量 = (CPU+3) / 4;

当CPU多于4个,收集线程占用的CPU资源多于25%,对用户程序影响可能较大;不足4个时,影响更大。

2.CMS所需要的空间比其他垃圾收集器大

由于在垃圾收集阶段用户线程还需要运行,那就需要预留足够的内存给用户线程使用,CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集。可以理解为CMS所需要的空间比其他垃圾收集器大;

-XX:CMSInitiatingOccupancyFraction  指定当老年代空间使用的阈值达到多少才进行一次CMS垃圾回收。(JDK1.5默认值为68%;JDK1.6变为大约92%)

CMS并发清理阶段用户线程还在运行着,会产生新的垃圾(留待下一次清理),这一部分垃圾称为“浮动垃圾”。

3.Concurrent Mode Failure 失败

CMS的垃圾清理和应用线程是并行进行的,如果在并行清理的过程中老年代的空间不足以容纳应用产生的垃圾,则会抛出“concurrent mode failure”。

会临时启用Serial Old收集器来进行垃圾收集,此时应用线程暂停,停顿时间更长。

所以 "-XX:CMSInitiatingOccupancyFraction"不能设置得太大。

4.产生大量碎片

由于CMS基于"标记-清除"算法,所以会产生碎片。产生大量不连续的内存碎片会导致分配大内存对象时,无法找到足够的连续内存,从而需要提前触发另一次Full GC动作。

  • -XX:+UseCMSCompactAtFullCollection此参数从JDK 9开始废弃)用于CMS不得不进行Full GC时开启内存碎片的合并整理过程;合并整理过程无法并发,停顿时间变长;默认开启;
  • -XX:+CMSFullGCsBeforeCompaction此参数从JDK 9开始废弃)设置执行多少次不压缩的Full GC后,来一次压缩整理;默认为0,也就是说每次都执行Full GC,不会进行压缩整理;

7.G1收集器

G1 的全称是 Garbage-First,意为垃圾优先,哪一块的垃圾最多就优先清理它。

G1 最主要的设计目标是:降低STW的停顿时间,将停顿的时间和分布变的可预期、可配置。

G1收集器的特点

  1. Region:G1将真个堆划分为多个大小相等的独立区域(regison)。
  2. 并行与并发:利用 多个 CPU来缩短 Stop-The-World 停顿时间(并行);让垃圾收集与用户程序同时执行(并发)。
  3. 分代收集:虽然保留了新生代和老年代,但能独立管理整个GC堆,无需与其他收集器搭配;
  4. 空间整合:从整体看是基于“标记-整理”算法;从局部上看是基于“标记-复制”算法实现的。所以不会产生内存碎片。
  5. 可预测的停顿:

G1收集器之所以能建立可预测的停顿时间模型,是因为:

  1. 它可以有计划地避免在整个Java堆中进行全区域的垃圾收集。
  2. G1跟踪各个Region获得其收集价值大小,后台维护一个优先列表
  3. 每次根据允许的收集时间,优先回收价值最大的Region,这样就保证了效率。

应用背景

1.面向服务端应用

针对具有大内存、多处理器的机器;为需要低GC延迟,并具有大堆的程序提供解决方案。如:在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒;

2.用来替换掉JDK1.5的CMS收集器

  1. 超过50%的Java堆被活动数据占用;
  2. 对象分配频率或年代提升频率变化很大;
  3. GC停顿时间过长(长与0.5至1秒)。

参数

  1. "-XX:+UseG1GC":指定使用G1收集器;
  2. "-XX:InitiatingHeapOccupancyPercent":当整个Java堆的占用率达到参数值时,开始并发标记阶段;默认为45;
  3. "-XX:MaxGCPauseMillis":为G1设置暂停时间目标,默认值为200毫秒;
  4. "-XX:G1HeapRegionSize":设置每个Region大小,范围1MB到32MB;目标是在最小Java堆时可以拥有约2048个Region;

回收价值:回收所获得的空间大小以及回收所需时间

注意:G1与前面的垃圾收集器有很大不同,它把新生代、老年代的划分取消了!

这意味着,在收集过程中完成了堆的压缩(至少是部分堆的压缩),这样也就不会有CMS内存碎片问题的存在了。

  1. G1算法将堆划分为若干个区域(Region),它仍然属于分代收集器。
  2. 部分区域为新生代,收集依然暂停应用线程,将存活对象拷贝到老年代或者Survivor空间。
  3. 部分区域为老年代,G1收集器通过将对象从一个区域复制到另外一个区域,完成了清理工作。
  4. 还有一种特殊的区域,叫Humongous区域。

Humongous区域

  • 如果一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象,默认分配在 年老代,但如果它存活期短,就会对垃圾收集器造成负面影响。
  • 为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。
  • 如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有 时候不得不启动Full GC。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/14670.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Push-Relabel算法相关阅读

Push-Relabel算法相关阅读1.Push-Relabel算法思想2.Push-Relabel算法原理示意图3.Push-Relabel算法具体实例4. 网络流各类算法简单总结与比较5. Push-Relabel 预流推进算法6. Push-Relabel算法(最大流)1.Push-Relabel算法思想 对于一个网络流图: 该算法直观可以这样理解&#…

java乱码问题一次性解决

在我们编码生活中&#xff0c;最常见的就是乱码&#xff0c;我也是遇到好几次&#xff0c;现在我整理一下所有乱码的解决方式&#xff0c;可治99%乱码问题 设置文件编码属性 修改当前 Web 项目 Tomcat Server 的虚拟机输出选项 -Dfile.encodingUTF-8 IntelliJ IDEA 中自定义…

AntDB入选《2022爱分析·信创厂商全景报告》

近日&#xff0c;AntDB数据库成功入选《2022爱分析信创厂商全景报告》信创数据库全景地图。报告综合考虑企业关注度、行业落地进展等因素&#xff0c;遴选出在信创市场中具备成熟解决方案和落地能力的厂商。 图1 AntDB数据库入选证书 报告指出&#xff0c;数据库作为企业存储、…

​力扣解法汇总790. 多米诺和托米诺平铺

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 有两种形状的瓷砖&#xff1a;一种是 2 x 1 的多米诺形&#xff0c;另一种是形如…

dubbo:docker安装dubbo-admin、zookeeper

0.引言 我们在搭建dubbo框架时&#xff0c;需要安装一个dubbo-admin来管理服务已经配置文件&#xff0c;今天我们来看看如何通过docker快速搭建一个dobbo-admin 1. 安装 1、首先到dockerhub上搜索dubbo-admin的镜像源 2、可以看到两个引用较高的镜像源&#xff0c;第一个是a…

了解区块链延迟和吞吐量

大家鲜少提到如何正确地测量一个&#xff08;区块链&#xff09;系统&#xff0c;但它却是系统设计和评估过程中最重要的步骤。系统中有许多共识协议、各种性能的变量和对可扩展性的权衡。 然而&#xff0c;直到目前都没有一种所有人都认同的可靠方法&#xff0c;能够让人进行…

Java#11(字符串练习)

目录 一.遍历字符串 1.public char charAt(int index): 根据索引返回字符 2.public int length(): 返回此字符串的长度 3.数组的长度:数组名.length 4.字符串的长度: 字符串对象.length() 二.统计字符个数 前提基础了解: 三.反转字符串 如何思路清晰的定义方法? 一.遍…

力扣(LeetCode)891. 子序列宽度之和C++)

数学推理 贡献法 由题意可知&#xff0c;子序列的内部顺序不影响宽度&#xff0c;所以可以对子序列排序。得到正序序列。 如 1234561~2~3~4~5~61 2 3 4 5 6 &#xff0c; 序列中数字 444 的下标 i3i3i3 &#xff0c;对于数字 444 &#xff0c; 最大值为 444 的子序列个数为 2…

Web前端开发技术课程大作业——HTML5旅游景区景点(13页面)HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

A-Level经济例题解析及练习Computing MPL and VMPL

知识点&#xff1a;Computing MPL and VMPL例题&#xff1a; Question: Computing MPL and VMPL P $5/bushel. Find MPL and VMPL, fill them in the blank spaces of the table. Then graph a curve with VMPL on the vertical axis, L on horizontal axis.解析&#xff1a;…

891. 子序列宽度之和(每日一难phase3-4)

891. 子序列宽度之和 一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。 给你一个整数数组 nums &#xff0c;返回 nums 的所有非空 子序列 的 宽度之和 。由于答案可能非常大&#xff0c;请返回对 109 7 取余 后的结果。 子序列 定义为从一个数组里删除一些&…

简单工厂模式、工厂模式、抽象工厂模式和加入反射、配置优化后的抽象工厂模式之间的关系和区别

通过两张图简单解释一下什么是简单工厂模式、工厂模式、抽象工厂模式 简单工厂模式是属于创建型模式&#xff0c;又叫做静态工厂方法&#xff08;Static Factory Method&#xff09;模式&#xff0c;但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种…

Mac上 Word安装Mendeley插件

Mac上 Word安装Mendeley插件问题背景解决方法针对Mendeley Desktop针对Mendeley Reference Manager参考链接问题背景 可能因如同时安装了Word和WPS等&#xff0c;导致Word上安装Mendeley插件失败&#xff08;Unable to install the Microsoft Word Plugin&#xff09;。目前网…

协同细菌觅食优化算法(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

知识蒸馏IRG算法实战:使用ResNet50蒸馏ResNet18

摘要 复杂度的检测模型虽然可以取得SOTA的精度&#xff0c;但它们往往难以直接落地应用。模型压缩方法帮助模型在效率和精度之间进行折中。知识蒸馏是模型压缩的一种有效手段&#xff0c;它的核心思想是迫使轻量级的学生模型去学习教师模型提取到的知识&#xff0c;从而提高学…

Golang入门笔记(11)—— 包

使用包的原因&#xff1a; 1.不可能把所有的不同业务功能的函数都放在一个源文件中&#xff0c;这样不便于管理。通常的做法是&#xff1a;我们会把具有相同一些功能和业务的维度的函数&#xff0c;分门别类的放在不同的源文件中。 2.不同的包名&#xff0c;可以解决两个函数…

Java面对对象的特征之二:继承性 :why?

一、继承性的好处&#xff1a; 减少了代码的冗余&#xff0c;提高了代码便于功能的扩展为之后的多态性的使用&#xff0c;提高了前提 二、继承性的格式&#xff1a;class A extends B{} A:子类、派生类、subclass B&#xff1a;父类、超类、基类、superclass 提现&#xff1…

数据中台解决方案-最新全套文件

数据中台解决方案-最新全套文件一、建设背景面临的挑战1、数据孤岛2、管理困难3、感知不强4、融合不足5、响应滞后二、思路架构三、建设方案四、获取 - 数据中台全套最新解决方案合集一、建设背景 在数字化转型及大数据战略布局背景下&#xff0c;建设大数据平台及数据应用。其…

idea连接kerberos认证的hive

其实用dbeaver连接hive就可以了。但是呢&#xff0c;idea也有这个功能&#xff0c;本着研究下的想法就试试。 结果最后成功了 最后记录下。 参考文章。感觉不太行 PyCharm,idea通过插件database连接带Kerberos的hive_不饿同学的博客-CSDN博客 里面提到了两个解决办法&#…

D. Non-zero Segments(前缀和)

Problem - 1426D - Codeforces 题意: 科利亚得到一个整数数组a1,a2,...,an。这个数组既可以包含正整数也可以包含负整数&#xff0c;但是Kolya不喜欢0&#xff0c;所以这个数组不包含任何零。 Kolya不喜欢他的数组中某些子段的总和为0&#xff0c;子段是数组中一些连续的元素…