JVM垃圾回收,参数,强 软 弱 虚,常见错误OOM,与微服务结合等---个人笔记四

一: 什么是垃圾回收?

程序运行必然需要申请内存资源,无效的对象会占有内存导致内存溢出.
1.1:C/C++语言的垃圾回收
通过delete释放内存资源
1.2:java垃圾回收
有自动垃圾回收机制(GC)

二 jvm模型

在这里插入图片描述

在这里插入图片描述

三:垃圾回收常见算法:

引用计数法,标记清除法,标记压缩法,复制算法,分代算法
3.1:引用计数法
特点:历史悠久
原理:任何对一个对象的引用,这个对象引用计数器就+1,当没有被引用(计数器为0),就回收
优点:
~实时性高,一有0引用对象就回收
~区域性,更新对象计数器只影响本对象,不扫描全部对象
~垃圾回收过程中,无需挂起,申请内存不足抛OutOfMember异常
缺点:
~每次都需要更新计数器浪费性能
~即使内存够还需运行计数器,浪费性能
~无法解决循环引用问题(最大缺点):两个对象互相引用对方
在这里插入图片描述
可以做GC Roots的对象
虚拟机栈中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI引用的对象(Native方法)

3.2标记清除法
特点:
~标记:从根节点开始标记引用的对象可达性分析
~清除:未被标记引用的对象计算垃圾对象开始清除
原理:
当内存没有了,开始运行GC线程开始标记工作,从root对象可达的对象标记为存活对象.清理未被标记的对象.
优点:
~解决了循环引用的问题
缺点:
~效率低:标记和清除两个动作需要扫描全部对象
~碎片化严重:被回收的对象可能位于内存的各个角落,被清理后的内存不连贯

3.3标记压缩算法
特点:
在标记清除算法基础上做了优化
原理:
当内存没有了,开始运行GC线程开始标记工作,从root对象可达的对象标记为存活对象.将存活对象压缩到内存的一端,并清理未被标记的对象.
优点:
~解决了循环引用问题
~解决了标记清除算法的碎片化问题
缺点:
~对存活对象的移动影响性能

3.4复制算法
原理:
原内存空间被一分为二,每次只用一块,垃圾回收时,将还使用的对象复制到另一个空间,把这个空间清空
过程:
a.在GC开始时,对象只存在Eden区和名为"From"的Survivor区,名为"To"的Survivor区是空的
b.GC开始执行,Eden区存活的对象都会被复制到"To",而"From"区存活对象根据他们的年龄值决定去向(年龄值可以通过-XX:MaxTenuringThreshold设置),年龄达到一定值的对象区年老代,没有达到阈值的对象复制到"To"
c.GC完成后,Eden区和From区都被清空,然后"From"和"To"交换角色,保证名为To的Survivor是空的
d.GC会一直重复次过程,直到"To"区满了,一旦满了将所有对象移动到年老代中.
在这里插入图片描述

优点:
~垃圾越多效率越高
~内存无碎片
缺点:
~垃圾越少,越不适用
~内存使用率低(分配2块内存同一时刻只用一块)

3.5分代算法
特点:
根据垃圾回收对象的特点合理的选择算法
比如:
年轻代适合复制算法
老年代适合标记清除或标记压缩算法

四:垃圾收集器

垃圾算法与垃圾收集器
GC算法(引用计数/复制/标清/标压)是内存回收的方法论,垃圾收集器是算法的落地实现
没有的完美的收集器,针对不同应用不同收集器
**java -XX:PrintCommandLineFlags -version查看垃圾回收器 ** 详见后文java参数–查看垃圾收集器

Server模式,Client模式(基本不会用)
32位操作系统(window)默认使用Client的jvm模式
32位操作系统,2G内存同时2个cpu以上用Server模式,低于该配置还是Client模式
64位only server模式

常见的垃圾收集器有:
Serial串行垃圾收集器, -XX:+UseSerialGC
Parallel并行垃圾收集器, -XX:+UseParallelGC -XX:+UseParallelOldGC 默认
CMS(并发)垃圾收集器, -XX:+UseConcMarkSweepGC
G1垃圾收集器 -XX:+UseG1GC
…详见下文:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

4.1串行垃圾收集器UseSerialGC

特点:
单线程进行垃圾回收
原理:
STW(Stop-The-World):垃圾回收时只有一个线程在工作,并且所有的java线程都要暂停等待垃圾回收完毕
实现:
配置JVM参数: -XX:+UseSerialGC
开启后会使用 : Serial(Young区使用) + Seral Old(Old区使用) 的收集器组合
表示: 新生代`老年代都会使用串行回收收集器, 新生代使用复制算法 老年代使用标记-压缩算法

4.2并行垃圾收集器UseParallelGC 默认
特点:
并行垃圾收集器收集过程中也会暂定应用程序,只是并行执行速度更快

原理:
多线程进行垃圾回收

4.2.1ParNew垃圾收集器 UseParNewGC

特点:
工作在年轻代上,只是将串行垃圾收集器改为了并行

实现:
配置JVM参数: -XX:UseParNewGC 启用ParNew收集器,只影响新生代的收集,不影响老年代
开启后会使用: ParNew(Young区用) + Serial Old的收集器组合,新生代使用复制算法,老年代采用标记-压缩算法

4.2.2ParallelGC垃圾收集器 UseParallelGC UseParallelOldGC

特点:
1.也是并行垃圾收集器,
2.同时工作在年轻代和老年代,
3.有可控的系统吞吐量参数(更灵活高效):Thoughput=运行用户代码时间/(运行用户代码时间+垃圾收集时间),
程序运行100分钟,垃圾收集时间1分钟,吞吐量就是99%…高吞吐量意味高效利用CPU时间

4.自适应调节策略,也是ParallelScavenge收集器与ParNew收集器的区别
虚拟机会根据系统运行情况收集性能监控信息,动态调整参数提供最合适的停顿时间(-XX:MaxGCPauseMillis)或最大吞吐量

实现:
-XX:+UseParallelGC 年轻代使用ParallelGC垃圾回收器,老年代使用串行回收器。
-XX:+UseParallelOldGC 年轻代使用ParallelGC垃圾回收器,老年代使用ParallelOldGC垃圾回收器。
上面两个参数可互相激活 使用Parallel Scavenge收集器

开启后会使用:新生代使用复制算法,老年代使用标记-压缩算法

如下图:
java6之前 Parallel Scavenge(年轻代) + Serial Old(MSC 老年代) 的组合
只能保证新生代的吞吐量优先,无法保证整体吞吐量

java8之后 Parallel Scavenge + Parallel Old 的组合
Parallel Old 可以为老年代同样提供吞吐量优先的垃圾收集器
在这里插入图片描述

-XX:MaxGCPauseMillis
设置最大的垃圾收集时的停顿时间,单位为毫秒 需要注意的时,ParallelGC为了达到设置的停顿时间,可能会调整堆大小或其他 的参数,如果堆的大小设置的较小,就会导致GC工作变得很频繁,反而可能会 影响到性能。
该参数使用需谨慎。
-XX:GCTimeRatio
设置垃圾回收时间占程序运行时间的百分比,公式为1/(1+n)。
它的值为0~100之间的数字,默认值为99,也就是垃圾回收时间不能超过1%
-XX:UseAdaptiveSizePolicy
自适应GC模式,垃圾回收器将自动调整年轻代、老年代等参数,达到吞吐量、堆大小、停顿时间之间的平衡。
一般用于,手动调整参数比较困难的场景,让收集器自动进行调整。

-XX:ParallelGCThreads=数字N 表示启用多少个GC线程
cpu>8 N=8/8
cpu<8 N=实际个数

4.3CMS垃圾收集器UseConcMarkSweepGC
特点:
并发,
标记清除算法
针对老年代垃圾回收
获取最短停顿时间为目标的收集器
适用于B/C系统的服务器,重视服务器的响应速度,希望系统停顿时间最短
适用于内存大,cpu核数多的服务器应用, 也是G1出现之前的大型应用首选收集器

实现:
-XX:+UseConcMarkSweepGC 开启该参数后会自动将 -XX:UseParNewGC打开
开启该参数后,使用ParNew(Young区用) + CMS(Old区用) + Serial Old 的收集器组合
Serial Old作为CMS出错的后备收集器

执行过程:

1.闲置等待
2.初始标记,标记root,会导致STW;
3.并发标记,与用户线程同时运行
4.预清理,与用户线程同时运行
5.重新标记,会导致STW,由于在并发标记时是与用户线程同时运行,有可能用户线程在并发标记时常见新对象引用所以这里重新标记
6.并发清理,与用户线程同时运行
7.调整堆大小,设置CMS在清理后进行内存压缩,清理内存的碎片
并发重置状态等待下次CMS触发,与用户线程同时运行

优点:
并发收集低停顿

缺点:
1.由于并发(一个cpu即干这个又干那个)进行,CMS在收集与应用线程会同时增加对的占用,
CMS必须在老年代用尽前完成垃圾回收,否则CMS回收失败时,
触发担保机制,串行老年代收集器将会以STW进行一次GC,大量时间被停顿
2.标记清除算法会导致大量的碎片,老年代会随着应用时长被逐步耗尽,最后将不得不,
触发担保机制,对压缩,
-XX:CMSFullGCsBeForeCompaction (默认0,即每次都进行内存压缩整理),来指定多少次CMS收集后,进行一次压缩的Full GC

4.4 Serial Old 垃圾收集器
特点:
单线程收集器
使用标记压缩算法
运行在Client默认的java虚拟机默认的年老代垃圾收集器
在Server模式下,有两个用途

  1. 在jdk1.5之前版本与新生代的Parallel Scavenge收集器搭配使用 (Parallel Scavenge + Serial Old)
    2.作为老年代版本中使用CMS收集器的后备垃圾收集方案

实现: 实现不了java8被优化掉了,没有了

-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialOldGC

4.5G1垃圾收集器(!!!)

在这里插入图片描述

特点:
1.G1是jdk7正式使用的垃圾收集器,官方计划在jdk9将G1变成默认垃圾收集器替代CMS
2.充分利用多CPU,多核环境硬件优势,尽量缩短STW
3.整体采用标记-压缩算法,局部通过复制算法,不会产生内存碎片
4.宏观上G1取消了年轻代,老年代的物理划分,取而代之的是将堆分为若干个区域(Region),这些区域包括了逻辑上的年轻代,年老代并且每个分区可能随着G1的运行在不同代之间前后切换

G1的设计原则是简化JVM性能的调优,开发人员只需要三步就可以完成调优:
a.开启G1垃圾收集器
b.设置堆的最大内存
c.设置最大的停顿时间
G1提供了三种垃圾回收模式 : Young GC, Mixed GC 和FullGC分别用于不同条件

原理:
Region区域化垃圾收集器: jvm启动会自动设置子区域的大小,
我们不需要对单独的每个代进行设置了,也不用担心每个代的内存是否够用,
化整为零,避免全内存扫描,只需要按照区域进行扫描
同时在
堆使用上,G1不要求对象的存储一定是物理上连续的,只要逻辑上连续即可,
-XX:G1HeapRegionSize=n可指定分区大小(1MB-32MB,且必须是2的幂),默认将整个堆划分为2048个分区(最大内存为:32MB*2048=64G)
-XX:MaxGCPauseMillis=n 最大GC停顿时间,这是个软目标,JVM将尽可能(但不保证)停顿小于这个时间
-XX:InitiatingHeapOccupancyPercent=n 堆占用了多少的时候触发GC,默认是45
-XX:ConcGCThreads=n 并发GC使用的线程数
-XX:G1ReservePercent=n 设置作为空闲空间的预留内存百分比,降低目标空间溢出的风险,默认是10%

在G1划分的Region区域中,年轻代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到年老代或者Survivor空间,
G1划分的Region区域中,老年代 收集器通过将对象从一个区域复制到另一个区域,完成清理工作
这就意味着,在正常处理过程中,G1完成了堆的压缩(至少是部分压缩),不会有cms内存碎片问题了

4.5.1G1的Humongous区

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

4.5.2Young GC

Young GC对Eden区进行GC的,它在Eden区空间耗尽才会触发.
~Eden空间的数据移动到Survivor空间,如果Survivor空间不够,Eden空间部分数据会直接晋升到年老代空间
~Survivor区的数据移动到新的Survivor区,也有部分数据晋升到老年代空间
~最终Eden空间数据为空,GC停止工作,应用线程继续工作

在这里插入图片描述
在这里插入图片描述
Young GC的回收步骤
在这里插入图片描述

4.5.2.1Remembered Set(已记忆集合)
在GC年轻代的对象时,我们如何找到年轻代中的根对象呢??
根对象可能存在与年轻代也可能存在与老年代中,全盘扫描老年代会使性能降低
于是G1提出了RSet概念::::用来跟踪指向某个堆内的对象引用

在这里插入图片描述

每个Region初始化时,都会初始化一个RSet,该集合用来记录并跟踪其他的Region指向该Region中对象的引用,每个Region默认按照512KB划分成多个Card,所以RSet需要记录的东西就是 xxRegion的 xxCard

**

4.5.3Mixed GC

**
当老年代的对象越来越多时候,虚拟机会触发一个混合的垃圾回收器(Mixed GC),
这个算法不是一个Oid GC,它除了回收整个Young Region还会回收一部分的Old Region,
注意 :::是一部分老年代不是全部的老年代!!!
可以选择哪些old region进行收集,从而可以对垃圾回收的耗时进行控制,
Mixed GC的触发:::
由参数-XX:InitiatingHeapOccupancyPercent=n 决定.
默认是45%(当老年代大小占整个堆大小百分比为45%触发)
其步骤::
a.全局并发标记
b.拷贝存活对象

4.5.3.1全局并发标记
步骤:
a.初始标记
标记从根节点直接可达对象,这个阶段会指向一次年轻代GC,会产生全局停掉STW
b.根区域扫描
G1 GC在初始标记的存活区扫描低老年代的引用,并标记被引用的对象
该阶段与应用程序同时运行,并且只有该阶段完成后,才可以下一个STW年轻代的垃圾回收
c.并发标记
G1 GC在整个堆查找可访问的对象(存活对象)
该阶段与应用程序同时运行,可以被STW年轻代垃圾回收打断
d.重新标记
该阶段是STW回收,因为程序在运行,是针对上一次的标记进行的修正
e.清除垃圾
清点和重置标记状态,该阶段会STW,
这个阶段并不会实际上区做垃圾收集,等待evacuation阶段来回收

4.5.3.2拷贝存活对象
Evacuation阶段是全暂停的,
该阶段把一部分Region里或的对象拷贝到另一部分Region中,从而实现垃圾回收清理

4.5.4G1收集器的参数


full GC堆的全盘清理
java垃圾收集手册

4.5.5 对G1垃圾收集器的优化建议

年轻代大小问题
避免使用-xmn选项或-XX:NewRatio等其他相关选项显示设置年轻代大小
固定年轻代大小会覆盖暂停时间目标
暂停时间目标不用太严苛
G1 GC的吞吐量弥补是90%的应用程序时间和10%的垃圾回收时间
评估G1 GC的吞吐量时,暂停时间目标不要太严苛.目标太严苛表示你愿意承受更多的垃圾回收开销,从而影响到吞吐量

4.6 G1比起CMS的优势

G1不会产生内存碎片
G1可以精确控制停顿,该收集器是把整个堆(新生代,老年代)划分成多个固定大小的区域
每次根据允许停顿的时间区收集垃圾最多的区域

4.6垃圾收集器的选择

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
单CPU或小内存,单机程序
-XX:+UseSerialGC

多CPU,需要最大吞吐量,如后台计算型应用
-XX:+UseParallelGC
或者
-XX:+UseParallelOldGC

多CPU,追求低停顿时间,需快速响应如互联网应用
-XX:+UseConcMarkSweepGC
-XX:+ParNewGC

在这里插入图片描述

五 jvm的参数

标准参数比较稳定,以后的java版本会保留
-help
-version 查看jvm版本
**-X参数(非标准参数)**不稳定,未来版本可能会改变
-Xint 强制JVM执行所有的字节码,运行速度低下
-Xcomp JVM在第一次使用时会把所有的字节码编译成 本地代码,从而带来最大程度的优化
-Xmixed 混合模式,将解释模式与编译模式进行混合使用 jvm默认的模式,是推荐使用的模式。
**-XX参数(使用率搞)**非标准参数 常用于jvm调优
boolean类型
格式 -XX:[±] 表示启用或禁用
如 -XX:+DisableExplicitGC 表示禁用手动调用gc操作,也就是说调用 System.gc()无效
非boolean类型
格式 -XX:= 表示属性的值为
如 -XX:NewRatio=1 表示新生代和老年代的比值

5.2查看jvm默认值
java -XX:+PrintFlagsInitial 查看初始默认值
在这里插入图片描述
java -XX:PrintFlagsFinal查看修改更新

运行java命令的同时打印参数:
在这里插入图片描述

在这里插入图片描述

= 没有该过
:= 人为修改过

java -XX:PrintCommandLineFlags -version
查看垃圾回收器
在这里插入图片描述
5.3、常用参数

-Xmx 设置堆内存最大大小
等价于-XX:MaxHeapSize,默认为物理内存的1/4

-Xms 设置堆内存初始大小
等价于-XX:InitialHeapSize 默认为物理内存的1/64

-Xss 设置单个线程栈的大小
等价于-XX:ThreadStackSize 默认为512-1024k

-Xmn
设置年轻代的大小
整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小,持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

-XX:MetaspaceSize
设置元空间大小(元空间的本质和永久代类似,都是对 JVM 规范中的方法区的实现,不过元空间于永久代之间最大区别在于,元空间并不在虚拟中,而是使用本地内存,因此默认情况下,元空间的大小仅受本地内存限制)
元空间默认比较小,我们可以调大一点

-XX:+PrintGCDetails
输出详细 GC 收集日志信息
设置 JVM 参数为: -Xms10m -Xmx10m -XX:+PrintGCDetails

-XX:SurvivorRatio
设置新生代中 eden 和 S0/S1 空间比例
默认 -XX:SurvivorRatio=8, Eden : S0 : S1 = 8 : 1 : 1

-XX:NewRatio
配置年轻代和老年代在堆结构的占比
默认 -XX:NewRatio=2 新生代占1,老年代占2,年轻代占整个堆的 1/3

-XX:MaxTenuringThreshold
设置垃圾最大年龄,必须是0-15
在这里插入图片描述
-XX:MaxGCPauseMillis
设置最大的垃圾收集时的停顿时间,单位为毫秒 需要注意的时,ParallelGC为了达到设置的停顿时间,可能会调整堆大小或其他 的参数,如果堆的大小设置的较小,就会导致GC工作变得很频繁,反而可能会 影响到性能。
该参数使用需谨慎。

-XX:GCTimeRatio
设置垃圾回收时间占程序运行时间的百分比,公式为1/(1+n)。
它的值为0~100之间的数字,默认值为99,也就是垃圾回收时间不能超过1%

-XX:UseAdaptiveSizePolicy
自适应GC模式,垃圾回收器将自动调整年轻代、老年代等参数,达到吞吐量、堆大小、停顿时间之间的平衡。
一般用于,手动调整参数比较困难的场景,让收集器自动进行调整。

-XX:ParallelGCThreads=数字N 表示启用多少个GC线程
cpu>8 N=8/8
cpu<8 N=实际个数
常用的参数调优:
在这里插入图片描述


当我们添加 -XX:PrintGCDetails查看垃圾回收的细节情况
在这里插入图片描述
在这里插入图片描述
修改 -Xms10m -Xmx10m
在这里插入图片描述
作死,创建大于10m的对象,报OOM
在这里插入图片描述
运行后:
在这里插入图片描述
第一行GC参数的含义:
在这里插入图片描述
Full GC
在这里插入图片描述
在这里插入图片描述

六 强 软 弱 虚

强引用
java.lang.ref.Reference
死都不收
是照成OOM的原因之一
软引用
java.lang.ref.SoftReference
内存充足 不会 被回收
内存不足 会 被回收
用于堆内存敏感程序中
如:(高速缓存),
读取大量本地图片
—从硬盘读取严重影响性能,一次加载到内存易OOM
解决思路:
一个HashMap保存图片的路径和相应图片对象关联的软引用之间的映射关系,
内存不足JVM会自动回收这些缓存图片对象占用的空间
Map<String,SoftReference> imageCache = new HashMap<String,;SoftReference>();
弱引用
java.lang.ref.WeakReference
垃圾回收机制一运行就回收
虚引用
java.lang.ref.PhantomReference
和引用队列(ReferenceQueue)联合使用

作用:
跟踪对象被垃圾回收的状态
这个对象被收集器回收前需要被引用队列保存,
可以在所引用的对象被回收时收到一个系统通知或者后续添加进一步处理
PhantomReference的get方法返回的总是null
将被回收
在这里插入图片描述

在这里插入图片描述

七 jvm常见错误

StackOverflowError 栈溢出错误
在这里插入图片描述

OutOfMemoryError:java heap space 堆溢出错误,对象太多,太大
在这里插入图片描述

OutOfMemoryError:GC overhead limit exceeded
在这里插入图片描述
在这里插入图片描述

OutOfMemoryError: Direct buffer memory NIO程序情况下,jvm堆内存好好的,本地内存满了(不属于GC的管辖),抛出错误

在这里插入图片描述
OutOfMemoryError: unable to create new native thread 不能创建更多线程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

OutOfMemryError: Metaspace元空间溢出错误

在这里插入图片描述
在这里插入图片描述

八 与微服务spring-boot的结合

下图与本文毫无关联:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值