- 回收算法
- 标记清除
- 清除后分配规则
- 复制
- 标记整理
- 整理算法分类
- jvm参数
- 标准参数
- -X参数
- -XX参数
- 常见参数
- 垃圾收集器
- young区
- Serial
- ParNew
- Parallel Scavenge
- old区
- Serial Old
- Parallel Old
- CMS
- G1
- ZGC
- 常见问题:
标记: 找出内中需要回收的对象,并且把他们标记出来 清除: 清除掉被标记的对象,释放出他们的内存 缺点: 标记和清除两个过程比较耗时,效率不高 会产生大量内存碎片(剩余的内存不连续),碎片太多导致以后分配较大对象时无法找到足够的连续内存而不得不触发垃圾回收 用在old区回收清除后分配规则
1、首次适应算法: 首次适应算法(Fisrt-fit)就是在遍历空闲链表的时候,一旦发现有大小等于需要的大小之后,就立即把该块分配给对 象,并立即返回 2、最佳适应算法:就是在遍历空闲链表的时候,返回刚好等于需要大小的块 3、最差适应算法:就是在遍历空闲链表的时候,找出空闲链表中最大的分块,将其分割给申请的对象,其目的就是使得 分割后分块的最大化,以便下次好分配,不过这种分配算法很容易产生很多很小的分块,这些分块也不能被使用
将内存划为两块相同的部分,每次只是用其中一块;当其中一块内存使用完,将已存活的对象复制到另一块区域中, (移动过后使得内存连续,避免内存连续)再将使用过的那一块内存空间清除掉 缺点:空间利用率低 young区中的两个s区就是用的复制算法(old区对象存活时间长,没必要赋值来复制去)标记整理
就是在标记清除的基础上再进行整理,避免内存碎片 用在old区回收
1、随机整理:对象的移动方式和它们初始的对象排列及引用关系无关 双指针回收算法:实现简单且速度快,但会打乱对象的原有布局 2、线性顺序:将具有关联关系的对象排列在一起 3、滑动顺序:将对象“滑动”到堆的一端,从而“挤出”垃圾,可以保持对象在堆中原有的顺序 Lisp2算法(滑动整理算法):需要在对象头用一个额外的槽来保存迁移完的地址 单次遍历算法:滑动回收,实时计算出对象的转发地址而不需要额外的开销 引线整理算法:可以在不引入额外空间开销的情况下实现滑动整理,但需要2次遍历堆,且遍历成本较高jvm参数 标准参数
每个JDK版本都不会变的
java -xxx
-version -help -server -cp-X参数
非标准参数,也就是在JDK各个版本中可能会变动
java -xx
-Xint 解释执行 -Xcomp 第一次使用就编译成本地代码 -Xmixed 混合模式,JVM自己来决定-XX参数
非标准化参数,相对不稳定,主要用于JVM调优和Debug
格式1、 -XX:[+-]: +或-表示启用或者禁用name属性;例如:-XX:+UseCompressedClassPointers(开启指针压缩) 格式2、 -XX = 表示name属性的值是value;例如:-XX:InitialHeapSize=258496576(初始化堆大小)
缩写:
-Xms1000M等价于-XX:InitialHeapSize=1000M -Xmx1000M等价于-XX:MaxHeapSize=1000M -Xss100等价于-XX:ThreadStackSize=100
查看所有参数:java -XX:+PrintFlagsFinal -version
:=标识不是默认,修改过(可能是jvm根据系统初始化、启动时添加参数)`
查看修改过的参数:java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=258496576 -XX:MaxHeapSize=4135945216 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
设置参数的方式
1、开发工具中设置比如IDEA,eclipse 2、运行jar包的时候:java -XX:+UseG1GC xxx.jar 3、web容器比如tomcat,可以在脚本中的进行设置 4、通过jinfo实时调整某个java进程的参数(参数只有被标记为manageable的flags可以被实时修改)常见参数
| 参数 | 含义 | 说明 |
|---|---|---|
| -XX:CICompilerCount=3 | 最大并行编译数 | 如果设置大于1,虽然编译速度会提高,但是同样影响系统稳定性,会增加JVM崩溃的可能 |
| -XX:InitialHeapSize=100M | 初始化堆大小 | 简写-Xms100M |
| -XX:MaxHeapSize=100M | 最大堆大小 | 简写-Xms100M |
| -XX:NewSize=20M | 设置年轻代的大小 | |
| -XX:MaxNewSize=50M | 年轻代最大大小 | |
| -XX:OldSize=50M | 设置老年代大小 | |
| -XX:MetaspaceSize=50M | 设置方法区大小 | |
| -XX:MaxMetaspaceSize=50M | 方法区最大大小 | |
| -XX:+UseParallelGC | 使用UseParallelGC | 新生代,吞吐量优先 |
| -XX:+UseParallelOldGC | 使用UseParallelOldGC | 老年代,吞吐量优先 |
| -XX:+UseConcMarkSweepGC | 使用CMS | 老年代,停顿时间优先 |
| -XX:+UseG1GC | 使用G1GC | 新生代,老年代,停顿时间优先 |
| -XX:NewRatio | 新老生代的比值 | 比如-XX:Ratio=4,则表示新生代:老年代=1:4,也就是新生代占整个堆内存的1/5 |
| -XX:SurvivorRatio | 两个S区和Eden区的比值 | 比如-XX:SurvivorRatio=8,也就是(S0+S1):Eden=2:8,也就是一个S占整个新生代的1/10 |
| -XX:+HeapDumpOnOutOfMemoryError | 启动堆内存溢出打印 | 当JVM堆内存发生溢出时,也就是OOM,自动生成dump文件 |
| -XX:HeapDumpPath=heap.hprof | 指定堆内存溢出打印目录 | 表示在当前目录生成一个heap.hprof文件 |
| -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:g1-gc.log | 打印出GC日志 | 可以使用不同的垃圾收集器,对比查看GC情况 |
| -Xss128k | 设置每个线程的堆栈大小 | 经验值是3000-5000最佳 |
| -XX:MaxTenuringThreshold=6 | 提升年老代的最大临界值 | 默认值为 15 |
| -XX:InitiatingHeapOccupancyPercent | 启动并发GC周期时堆内存使用占比 | G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比. 值为 0 则表示”一直执行GC循环”. 默认值为 45. |
| -XX:G1HeapWastePercent | 允许的浪费堆空间的占比 | 默认是10%,如果并发标记可回收的空间小于10%,则不会触发MixedGC。 |
| -XX:MaxGCPauseMillis=200ms | G1最大停顿时间 | 暂停时间不能太小,太小的话就会导致出现G1跟不上垃圾产生的速度。最终退化成Full GC。所以对这个参数的调优是一个持续的过程,逐步调整到最佳状态。 |
| -XX:ConcGCThreads=n | 并发垃圾收集器使用的线程数量 | 默认值随JVM运行的平台不同而不同 |
| -XX:G1MixedGCLiveThresholdPercent=65 | 混合垃圾回收周期中要包括的旧区域设置占用率阈值 | 默认占用率为 65% |
| -XX:G1MixedGCCountTarget=8 | 设置标记周期完成后,对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧区域执行混合垃圾回收的目标次数 | 默认8次混合垃圾回收,混合回收的目标是要控制在此目标次数以内 |
| -XX:G1OldCSetRegionThresholdPercent=1 | 描述Mixed GC时,Old Region被加入到CSet中 | 默认情况下,G1只把10%的Old Region加入到CSet中 |
stw(stop the word):停止用户线程,只执行垃圾回收线程
young区 Serial优点:简单高效,拥有很高的单线程收集效率 缺点:收集过程需要暂停所有线程 算法:复制算法 适用范围:新生代 应用:Client模式下的默认新生代收集器ParNew
优点:在多CPU时,比Serial效率高。 缺点:收集过程暂停所有应用程序线程,单CPU时比Serial效率差。 算法:复制算法 适用范围:新生代 应用:运行在Server模式下的虚拟机中首选的新生代收集器Parallel Scavenge
Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器, 看上去和ParNew一样,但是Parallel Scanvenge更关注系统的吞吐量 吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间) 比如虚拟机总共运行了100分钟,垃圾收集时间用了1分钟,吞吐量=(100-1)/100=99%。 若吞吐量越大,意味着垃圾收集的时间越短,则用户代码可以充分利用CPU资源,尽快完成程序的运算任务。 -XX:MaxGCPauseMillis控制最大的垃圾收集停顿时间, -XX:GCRatio直接设置吞吐量的大小。old区 Serial Old
Serial Old收集器是Serial收集器的老年代版本,也是一个单线程收集器,不同的是采用"标记-整理算法",运行过程和Serial收集器一样。Parallel Old
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法进行垃圾回收,也是更加关注系统的吞吐量。CMS
采用的是"标记-清除算法",整个过程分为4步 (1)初始标记 CMS initial mark 标记GC Roots直接关联对象,不用Tracing,速度很快 (2)并发标记 CMS concurrent mark 进行GC Roots Tracing (3)重新标记 CMS remark 修改并发标记因用户程序变动的内容 (4)并发清除 CMS concurrent sweep 清除不可达对象回收空间,同时有新垃圾产生,留着下次清理称为浮动垃圾 由于整个过程中,并发标记和并发清除,收集器线程可以与用户线程一起工作,所以总体上来说,CMS收集器的内存 回收过程是与用户线程一起并发地执行的。 优点:并发收集、低停顿 缺点:产生大量空间碎片、并发阶段会降低吞吐量G1 ZGC 常见问题:
(1)串行
-XX:+UseSerialGC
-XX:+UseSerialOldGC
(2)并行(吞吐量优先):
-XX:+UseParallelGC
-XX:+UseParallelOldGC
(3)并发收集器(响应时间优先)
-XX:+UseConcMarkSweepGC
-XX:+UseG1GC
停顿时间->垃圾收集器 进行 垃圾回收终端应用执行响应的时间
吞吐量->运行用户代码时间/(运行用户代码时间+垃圾收集时间)
如何选择合适的垃圾收集器:
优先调整堆的大小让服务器自己来选择
如果内存小于100M,使用串行收集器
如果是单核,并且没有停顿时间要求,使用串行或JVM自己选
如果允许停顿时间超过1秒,选择并行或JVM自己选
如果响应时间最重要,并且不能超过1秒,使用并发收集器



