JVM垃圾收集器,GC,垃圾收集器种类,串行并行并发回收,STW,G1收集器,GC组合配置,GC内存选项配置,,GC辅助选项配置

传统C/C++程序内存需要开发者手动来进行分配和回收,常见的比如mallocfree来进行内存分配和回收,这样做虽然能够很大的自由度来对内存进行操作,但是也对程序的设计和开发者本身大代码水平有很高的要求,因为一不小心,分配的内存在没有作用后没有及时回收,随着系统运行的时间越来越长,系统耗费的内存会越来越多,最终会达到硬件资源的内存最大限制水平,从而会导致整个程序最终崩溃。
Java中内存的管理是交由虚拟机(JVM)管理的,开发者不用再去头疼内存的分配和回收,能够专心于其他业务代码的处理。那么有一个问题就必须考虑,如何能够让JVM的垃圾回收更高效,不同的场景是否需要不同的内存回收策略。
对于自动回收内存的语言来说,需要知道哪些对象能够被回收?目前有两种比较常见的垃圾标记算法,引用计数法根搜索算法
引用计数法:即判断一个内存实例是否仍然有其他对象引用它?如果没有则认为可以回收这块内存。引用计数法最大一个问题是循环引用问题,如:A应用了B,同时B也用了A,这样A,B之间形成了循环引用的闭环,永远不可能被回收。
根搜索算法:有的也叫可达性分析法,根搜索算法以根对象集合为起点,从上到下,搜索被根对象集合所连接的目标对象是否可达,如果对象不可达,就意味着该对象已经死亡,可以回收,此时可以在instanceOopDesc的Mark Word中将对象实例标记为已经死亡。
当对象被标记为已经死亡后,这时候GC就需要执行垃圾回收,释放掉可回收对象实例的内存空间,方便后续分配更多对象实例。
一般GC算法都是基于分代的概念,不同的代采用不同的算法。JVM中一般分为:新生代(Young Generatopm)和老年代(Old Generation)两个分代。一般对象分配都分配在新生代,当经历过数次GC后如果仍存活,则会升级为老年代。jvm中GC会混合不同代同时进行收集,一般有如下几种:
新生代收集:Minior GC/Young GC,新生代垃圾收集
老年代收集:Major GC/Old GC,老年代垃圾收集,目前只有CMS收集器只单独回收老年代
混合收集:Mixed GC,一般指整个新生代收集和部分老年代收集,目前G1收集器实现
整堆收集:Full GC收集整个Java堆和方法区
JVM常见三种垃圾回收算法:

  • 标记清除算法(Mark Sweep)
  • 复制算法(Copying)
  • 标记压缩(Mark Compact),有的也称为标记整理

标记清除算法是一种比较基础和常见的算法, 其处理逻辑很简单,分为两步,标记需要被回收的对象,释放对象内存。标记清除算法会随着对象数量的增多而效率低下,另外更大的问题是,清除后会导致内存不连续,出现很多内存碎片,可能会导致后续没有足够可用内存空间分配给较大对象。

为了解决标记清除算法在标记和清除两个阶段的执行效率,JVM提供了另外一种算法,复制算法。其基本思路是将内存空间分为两部分,A,B,对象首先分配在A上面,进行垃圾回收的时候直接将A中存活的对象复制到B中,然后将A整个回收清除。如果存活的对象占多数,这种复制会产生大量的内存开销,但如果只有少量的存活对象,每次复制都只有一小部分存活对象需要复制,开销在可控范围,同时由于是整块的清除和复制,这样后续能够连续的分配内存。这样解决了标记清除算法的两个问题。不过这样带来的问题时,可用的内存被一分为二,只能用到可用内存的一半。复制算法一般用于新生代,新生代中大量的对象在创建后都会很快消亡,存活的对象只有一小部分。JVM中一般分为老年代和新生代,而在新生代中又分为Eden和两个survivor空间,一般这三个比例为8:1:1,一般称为 Eden,From Survivor,To Survivor。复制算法会将Eden和From Survivor中存活的对象复制到To Survivro中去(From Survivor和To Survivor的定义不是一成不变的,第一次是From Suvrivor下次就变成了To Survivor)。这样下来,新生代中会浪费10%左右的空间.
标记压缩算法一般用于老年代。针对老年代中的对象一般存活时间比较长,一般不会进行频繁回收,JVM提供了标记压缩算法,其思想与标记清除算法类似,但是在回收时,并不是直接回收清除,而是将存活的对象移动到内存的一端,然后直接清理掉另外一端。
对于垃圾回收还有一个问题是,串行还是并行回收,并发还是STW(Stop The World)
串行回收指的是当垃圾回收器开始工作的时候,只有一个线程进行垃圾回收,同时进行垃圾回收的时整个应用程序工作线程会被暂停(Stop The World),当垃圾回收完成后,恢复之前的工作线程,一般采用复制算
并行回收值指的是垃圾回收的时候多个线程并行进行垃圾回收,同时进行垃圾回收的时候也会STW,垃圾回收完成之后,恢复之前的工作线程,一般采用复制算法
并发回收:针对串行回收和并行回收中出现的STW现象,如果在新生代或者说垃圾回收再很短的时间内就能完成,还是比较有用,但是如果像是老年代中存活了大量存活时间比较长的对象,则STW会持续比较长的时间,对于一些比较注重吞吐量的应用来说,这个是不能接受的,为此,JVM还提供了并发收集来剪短STW的时间。所谓并发收集是指在同一时间段内应用的工作线程和垃圾回收线程同时或交叉运行,但是需要注意的是,截止到目前JVM中没有一个收集器不需要STW,只是降低STW的时间
Serial收集器:串行回收,
ParNew收集器:并行回收
Parallel收集器:吞吐量优先。和ParNew一样基于并行回收,但是Parallel比较关注的是程序整体的吞吐量。-xx:GCTimeRatio来设置垃圾回收站JVM运行时间的比例。-XX:MaxGCPauseMills设置执行垃圾回收的时候STW的时间阈值。
CMS收集器:Concurrent Mart Sweep,降低延迟,基于并行回收,采用标记清除算法,老年代专用收集器.。一般分为如下4个阶段:

  1. 初始标记(Initial Mark),会有STW
  2. 并发标记(Concurrent Mark)
  3. 再次标记(Remark)会有STW
  4. 并发清除(Concurrent Sweep)

G1收集器:G1收集器主要是为了替代CMS收集器,基于并行和并发,低延迟以及暂停时间更加可控的区域化分代式垃圾收集器。G1收集器是具有革命性改变的设计,在java堆的设计上,重塑了整个java堆,虽然依然是基于分代回收的概念,但是并没有在实际物理存储上进行设计,只是逻辑上的分代,在物理上将整个堆分成了约2048个Region块,G1在进行垃圾回收的时候优先释放掉一些占用内存比较大的Region块,从而避免像以前一样扫描整个JAVA堆区。G1收集器与CMS类似,有如下几个阶段:

  1. 初始标记,会有STW,主要是标记Root-Region,
  2. 根区域扫描 ,扫描Root-Region中引用老年代的一些Region块
  3. 并发标记,找出存活的对象
  4. 再次标记 ,会有STW,标记存活对象
  5. 清除,
  6. 拷贝

GC组合配置

GC组合MiniorGCFull GC描述
-XX:+UseSerialGCSerial收集器串行回收Serial Old收集器串行回收
-XX:+UseParNewGCParNew收集器并行回收Serial Old收集器串行回收
-XX:+UseParallelGCParallel收集器并行回收Serial Old收集器串行回收
-XX:+UseParallelOldGCParallel收集器并行回收Parallel Old收集器并行回收
-XX:+UseConcMarkSweepGCParNew收集器并行回收缺省采用CMS收集器,备用采用Seial Old收集器串行回收-XX:+UseConcMarkSweepGC可以指定ParNew+CMS+Serial Old组合执行回收,优先使用ParNew+CMS,当ConcurrentMode Failur或Promotion Failed失败时,采用ParNew+Serial Old
-XX:+UseConcMarkSweepGC -XX:-useParNewGCSerial 收集器串行回收同上同上
-XX:+UseG1GCG1收集器并发、并行回收G1收集器并发、并行回收

GC内存选项

选项    默认值描述
-Xms物理内存的1/64, < 1GB设置java堆的初始内存,当可用的java堆内存<40%时候,会将内存调整到-Xmx所允许的最大值
-Xmx物理内存的1/4,<1GB设置java堆的最大内存,当可用的java堆区内存大于70%的时候,会将内存调整到-Xms允许的初始值
-Xmn设置新生代内存,-Xmn为Eden区域加2个Surivivor的空间的值,官方建议配置为整个堆的3/8
-XX:NewSize设置新生代内存初始值,起始和Xmn等价,推荐使用Xmn,相当于一次设置了NewSize/Max-NewSize的内存大小
-XX:MaxSize设置新生代最大内存
-XX:NewRatio新生代(Eden+2个Survivor)空间与老年代的壁纸,不包括永久代,,如-XX:NewRatio=4,表示新生代与老年代所占的内存比为1:4,如果设置了Xmn,则无需设置该项
-XX:PermSize物理内存的1/64设置方法区的初始内存
-XX:MaxPermSize物理内存的1/4设置方法区最大内存
Serial收集器-XX:MaxTenuringThresholdGC分代年龄设置,缺省新生代晋升到老年代的年龄是15
ParNew收集器同上同上
--XX:+UseAdaptiveSizePolicy动态调整java堆各个区域的内存大小,以及GC分代年龄
Parallel/Parallel Old收集器-XX:ParallelThreads垃圾收集器的线程数
--XX:+UseAdaptiveSizePolicy动态调整java堆各个区域的内存大小,以及GC分代年龄
--XX:MaxTenuringThresholdGC分代年龄设置,缺省新生代晋升到老年代的年龄是15
--XX:GCTimeRatio设置执行内存回收时间所占JVM运行总时间的比例,默认是99,计算方式为: 1/(1+N)
--XX:MaxGCPauseMills执行垃圾回收时,STW暂停时间的阈值,仅Parallel收集器有效
CMS收集器-XX:ParallelCMSThreads垃圾收集的线程数
--XX:CMSFullGCsBeforeCompaction执行多少次FullGC后对内存空间进行压缩整理
--XX:+UseCMSCompactAtFullCollection执行完FullGC后,是否对内存空间进行压缩整理
--XX:CMSInitiatingOccupancyFraction老年代代中内存使用率达到多少百分比执行来及回收,默认人为92%
-XX:+UseCMSInitiatingOccupancyOnly允许Hotspot jvm自己决定什么时候回收,默认为false
--XX:+CMSClassUnloadingEnabled方法区使用CMS收集器回收
--XX: CMSIncrementalMode单CPU使用增量模式
-XX:CMSInitiationPermOccupancyFraction方法区内存使用率达到阈值进行垃圾回收
G1收集器-XX:G1ReservePercent空闲空间预留内存的百分比,降低溢出风险,默认为10%
--XX:G1HeapRegionSize设置Region大小,2的幂,在1MB到32MB之间,根据最小的java堆大小划分大约2048个Region

GC辅助选项配置

选项描述
-XX:+PrintGC打印垃圾收集的基本信息
-XX:+PringGCDetails打印垃圾收集详细信息
-XX:+PringGCTimeStamps打印垃圾收集执行时间戳(基准时间)
-XX:+PringGCDateStamps打印垃圾收集执行时间戳(日期格式)
-XX:+PrintGCApplicationStoppedTime垃圾收集造成程序停顿时间
-XX:PrintTLAB打印TLAB空间使用情况
-XX:+PrintTenuringDistribution打印灭磁MiniorGC后新的存活周期的阈值
-XX:+PrintHeapAtGC打印垃圾回收前后堆栈信息
-Xloggc执行GC日志的输出路径

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值