JVM笔记3:Java垃圾收集算法与垃圾收集器

本文详细介绍了商业虚拟机的垃圾收集算法,包括标记-清除算法、复制算法、标记-整理算法及其在不同收集器(如Serial、ParNew、ParallelScavenge等)中的应用。重点讨论了新生代与老年代的内存分配策略、各算法的优缺点及如何通过调整参数以优化垃圾收集性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当前商业虚拟机的垃圾收集都采用“分代收集”算法,即根据对象生命周期的不同,将内存划分几块,一般为新生代和老年代,不同的代根据其特点使用最合适的垃圾收集算法

一,标记-清除算法:

该算法分为“标记”、“清除”2个过程,首先标记需要清除的对象,然后统一清除

这个算法有2个明显的缺点:

1,标记和清除的效率都不高

2,垃圾收集后,内存碎片化严重

 

二,复制算法:

将内存分大小相同的2块,每次只使用其中的一块。当一块中的内存耗光,则将还活着的对象复制到另一块,并清空原先的那一块

这个算法的优缺点都比较明显

优点是实现比较简单,效率也很高,而且没有内存碎片化的问题

缺点是最大的可用内存变为原先的二分之一,估计这谁也受不了

新生代的特点是每次垃圾收集后,依然存活的对象数量很少。如果针对新生代使用该算法,没必要保留二分之一的可用内存

可以将内存按照8:1:1的比例分为一块较大的Eden空间和2个较小的Survivor空间,每次只使用Eden空间和一个Survivor空间,比起原先50%的内存使用率,90%的内存使用率是可以接受的

内存回收时,将依然存活的对象拷贝至另一个Survivor空间,并清空原Survivor空间和Eden空间

按照新生代的特点,依然存活的对象是很少的,但是,如果一个Survivor空间无法提供足够的空间以存放依然存活的对象,该如何处理?答案是去老年代租借点内存用来救急

某些极端情况下,对象存活率有可能为100%,这时需要从老年代申请较多内存

 

三,标记-整理算法

同标记-清除算法的标记部分相同,然后让所有存活对象向一端移动,最后清除掉边界以外的部分

 

一,Serial收集器

新生代收集器,使用复制算法

单线程收集器

虚拟机-client模式下新生代的默认回收器

单线程进行垃圾收集,并且在其进行垃圾收集时,必须暂停其它所有工作线程,直到垃圾收集结束,这一过程(stop the world)由虚拟机在后台自动发起自动完成,会在用户不可见的条件下把用户所有正常工作线程全部停掉。当然如果停顿的时间很短是可以接受的,但是如果每次停顿5分钟,任何人都会崩溃

对于某些客户端程序,新生代占用的内存空间往往很小,此时停顿时间完全可以控制在毫秒级别,因此对于运行在client模式下的虚拟机,Serial收集器是个不错的选择

优点:简单高效(相对于其它收集器运行于单CPU环境下。没有线程分配的开销,可以获得最高的单线程垃圾收集效率)

 

二,ParNew收集器

新生代收集器,使用复制算法

多线程收集器

Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为与Serial收集器完全一样,依然会stop the world

很多虚拟机-server模式下的首选新生代收集器,主要原因是CMS收集器(老年代收集器)只能与Serial收集器或者ParNew收集器配合使用

默认开启的回收线程数与CPU个数相同(现代服务器动辄32个逻辑CPU将会导致ParNew收集器开启32个收集线程,这种情况下最好限制下收集线程个数)

-XX:ParallelGCThreads 多线程垃圾收集器内存回收开启的线程数量

 

三,Parallel Scavenge收集器

新生代收集器,使用复制算法

多线程收集器

该收集器的关注点与其它收集器的关注点不同,其它收集器的目标为尽可能缩短垃圾收集时用户线程的停顿时间,该收集器的目标为达到一个可控的吞吐量,吞吐量=运行用户代码时间/(运行用户代码时间+垃圾回收时间) 

停顿时间短则响应速度快,适合与用户交互比较多的应用;吞吐量大能够最高效的利用CPU时间,尽快完成运算任务,适合后台运算、交互不多的应用

GC拥有自适应调节策略。如果启用该策略,只需要设置好基本参数(-Xmx等),然后设置一个优化目标(最大垃圾收集时间或吞吐量大小),虚拟机会根据当前系统的运行状况收集性能监控信息,动态调整细节参数设置(例如:-XX:SurvivorRatio 新生代中Eden区与Survivor区的大小比率,默认为8,即Eden:survivor=8:1、-XX:PretenureSizeThreshold直接晋升老年代对象大小,超过这个大小的对象将直接在老年代分配,只有Serial和ParNew收集器认识这个参数-XX:MaxTenuringThreshold 晋升老年代对象年龄,每个对象在坚持过一次Minor GC后对象年龄+1,超过设置数值对象移动至老年代)以提供最合适的停顿时间和最大吞吐量

-XX:MaxGCPauseMillis 最大停顿时间,仅对Parallel Scavenge收集器生效

-XX:GCTimeRatio 吞吐量大小,默认值为99,即1%的GC时间,仅对Parallel Scavenge收集器生效

-XX:+UseAdaptiveSizePolicy 使用GC自适应调节策略

 

四,Serial Old收集器

老年代收集器,使用标记-整理算法

单线程收集器

Serial收集器的老年代版本

作为CMS收集器的后备收集器:当CMS收集器产生Concurrent Mode Failure时,将临时启动Serial Old收集器重新进行老年代的垃圾收集

 

五,Parallel Old收集器

老年代收集器,使用标记-整理算法

多线程收集器

JDK1.6提供,Parallel Scavenge收集器的老年代版本

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

 

六,CMS(Concurrent Mark Sweep)收集器

老年代收集器,使用标记-清除算法

多线程并发收集器

以达到最短的垃圾收集挺停顿时间为目标的收集器

该收集器的收集过程分为4个步骤:

1,初始标记 CMS initial mark:该步会stop the world,但耗时非常短,标记GC Root直接关联的对象

2,并发标记 CMS concurrent mark:耗时较长,用户线程可同时运行,标记至GC Root有可达路径的对象

3,重新标记 CMS remark:该步会stop the world,但耗时非常短。由于步骤2用户线程同步运行,此时主要修正因步骤二同步用户线程产生的对象标记变动

4,并发清除 CMS concurrent sweep:耗时较长,用户线程可同时运行

在耗时很长的并发标记阶段和并发清除阶段用户线程和收集线程都可同时工作,故而总体上来说,CMS收集器的内存回收是与用户线程一起并发执行的

虽然收集停顿时间短,但是也有不少缺点:

1,对CPU资源敏感,CMS收集器默认开启的收集线程数为(CPU数量+3)/4,如果CPU数量较少,会占用不少CPU处理资源

2,无法处理浮动垃圾,并且可能产生Concurrent Mode Failure从而导致另一次Full GC。

并发清除时(步骤4),用户线程是可以同时运行的,此时用户线程会产生新的垃圾,这部分垃圾在标记过程之后产生,本次GC已经不能进行标记后清除,只能留到下次GC时处理,被称为浮动垃圾

由于CMS的收集线程执行时,用户线程也是会同时执行的,导致CMS收集器无法像其它老年代收集器那样在老年代内存几乎耗尽时在进行GC,必须为用户线程预留部分内存(默认使用68%内存就会开启收集过程),如果预留内存无法满足用户线程的执行,将会出现Concurrent Mode Failure,此时虚拟机将会启动备用方案,调用Serial Old收集器执行一次Full GC,这将导致较长的收集停顿

-XX:CMSInitiationgOccupancyFraction 设置GC触发的百分比,默认为68%,太高会导致过多的Concurrent Mode Failure,太低则影响性能,仅对CMS收集器生效

3,由于采用标记-清除算法实现,会产生内存碎片

-XX:+UseCMSCompactAtFullCollection Full GC后提供内存整理,该过程是无法并发的,会导致性能下降,仅对CMS收集器生效

-XX:+CMSFullGCsBeforeCompation 设置进行完几次不进行压缩的Full GC后,进行一次附带压缩的Full GC,仅对CMS收集器生效

 

七,G1(Garbage First)收集器(前瞻)

使用标记-整理算法,不会产生内存碎片

可以非常精确的设定垃圾收集停顿时间:在一个长度为X毫秒的时间片内,垃圾收集最多消耗Y毫秒(比起Parallel Scavenge收集器单纯的一个最大停顿时间,真是精确太多了)

不同于其它收集器的收集范围为整个新生代或老年带,G1收集器将堆(包括新生代以及老年带)分为多个大小固定的区域,跟踪区域中的垃圾堆积情况并在后台维护一个优先级列表,每次根据允许的垃圾收集时间优先收集优先级最高的区域,这样可以保证在在有限的时间内获得最高的收集效率

 

收集器的组合使用:

-XX:+UseSerialGC 使用Serial+Serial Old的收集器组合

-XX:+UseParNewGC 使用ParNew+Serial Old的收集器组合

-XX:+UseConcMarkSweepGC 使用ParNew+CMS(Serial Old)的收集器组合

-XX:+UseParallelGC 使用Parallel Scavenge+Serial Old的收集器组合

-XX:+UseParallelOldGC 使用Parallel Scavenge+Parallel Old的收集器组合

 

PS:

Minor GC : 发生在新生代的GC,非常频繁,速度很快

Full GC/Major GC :发生在老年代的GC,一般会比Minor慢10倍以上

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC单片机电压测量”是一个以STC系列单片机为基础的电压检测应用案例,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC单片机凭借其低功耗、高性价比丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的单片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化单片机的硬件环境;“电压测量_uvopt.bak”“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为单片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到单片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供单片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC单片机对浮点数的支持情况,以及如何高效地存储显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
资源下载链接为: https://pan.quark.cn/s/abbae039bf2a 在 Android 开发中,Fragment 是界面的一个模块化组件,可用于在 Activity 中灵活地添加、删除或替换。将 ListView 集成到 Fragment 中,能够实现数据的动态加载列表形式展示,对于构建复杂且交互丰富的界面非常有帮助。本文将详细介绍如何在 Fragment 中使用 ListView。 首先,需要在 Fragment 的布局文件中添加 ListView 的 XML 定义。一个基本的 ListView 元素代码如下: 接着,创建适配器来填充 ListView 的数据。通常会使用 BaseAdapter 的子类,如 ArrayAdapter 或自定义适配器。例如,创建一个简单的 MyListAdapter,继承自 ArrayAdapter,并在构造函数中传入数据集: 在 Fragment 的 onCreateView 或 onActivityCreated 方法中,实例化 ListView 适配器,并将适配器设置到 ListView 上: 为了提升用户体验,可以为 ListView 设置点击事件监听器: 性能优化也是关键。设置 ListView 的 android:cacheColorHint 属性可提升滚动流畅度。在 getView 方法中复用 convertView,可减少视图创建,提升性能。对于复杂需求,如异步加载数据,可使用 LoaderManager CursorLoader,这能更好地管理数据加载,免内存泄漏,支持数据变更时自动刷新。 总结来说,Fragment 中的 ListView 使用涉及布局设计、适配器创建定制、数据绑定及事件监听。掌握这些步骤,可构建功能强大的应用。实际开发中,还需优化 ListView 性能,确保应用流畅运
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值