JVM(JVM原理/性能监控/故障定位/OOM)
2021-10-13 18:48:09 1 举报
AI智能生成
JVM
作者其他创作
大纲/内容
1.JDK,JRE,JVM之间的关系
JDK是Java开发工具包,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库
JRE是Java的运行环境,包括JVM标准实现及Java核心类库。
JVM是java虚拟机,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序
安装jdk时的会有两个jre文件夹
2.内存区域
1.java内存结构图
2. 运行时内存区域图
JDK 1.8之前
JDK 1.8
3. 运行时内存区域
1.2.1 程序计数器
当前线程所执行的字节码的行号指示器
线程私有
原因
1.2.2 虚拟机栈
是描述java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame) 用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成 的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程
Java虚拟机栈和栈帧:Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法
局部变量表
操作数栈:以压栈和出栈的方式存储操作数的
动态链接:每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态 连接(Dynamic Linking)。
方法返回地址:当一个方法开始执行后,只有两种方式可以退出,一种是遇到方法返回的字节码指令;一种是遇见异常,并且 这个异常没有在方法体内得到处理。
图片
线程私有
1.2.3 本地方法(Native Method)栈
Native方法本地方法栈与Java栈的作用和原理非常相似。
Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。
线程私有
1.2.4 方法区
存储已被JVM加载
每个类的信息(包括类的名称、方法信息、字段信息)
静态变量
常量
编译器编译后的代码
线程共享
1.2.5 堆
Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的)。
内存最大的一块,GC主要区域
从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以Java堆中还可以细分年轻代,老年代,元数据区
运行时常量池
JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池
线程共享
1.2.6 直接内存(jdk1.4 NIO引入的)
在JDK 1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,
它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。
避免在Java堆和Native堆中来回复制数据
1.3 java 内存分配
1.4 对象的一辈子理解
图片
3.java类加载机制
定义及过程
具体过程(七步)
1.加载
2.验证
3.准备
4.解析
5.初始化
6.使用
7.卸载
图片
JAVA中执行顺序
程序的赋值步骤
什么情况下需要开始类加载过程的第一个阶段加载
双亲委派模型
图片
类加载器
启动类加载器(Bootstrap ClassLoader)
扩展类加载器(Extendsion ClassLoader)
应用程序类加载器(Application ClassLoader)
自己定义的类加载器
为什么要设计双亲委派机制
沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心 API库被随意篡改
避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一 次,保证被加载类的唯一性
Tomcat打破双亲委派机制
图片
有哪些类加载器
同一个JVM内,两个相同包名和类名的类对象可以共存,因为他们的类加载器可以不一样,所以看两个类对象是否是同一个,除了看类的包名和类名是否都相同之外,还需要他们的类加载器也是同一个才能认为他们是同一个。
模拟实现Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离
模拟实现Tomcat的JasperLoader热加载
4.垃圾回收机制
1. 那些区域需要回收
2. 对象的创建
1.类加载检查
虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中,定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
2.分配内存
在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。分配方式有 “指针碰撞” 和 “空闲列表” 两种,选择那种分配方式由 Java 堆是否规整决定,而 Java 堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。
3.初始化零值
内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
4.设置对象头
初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是那个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。
5.执行 init 方法
在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,<init> 方法还没有执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 <init> 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。
3. 垃圾收集算法
1. 标记-清除
适用场合
存活对象较多的情况下比较高效
适用于年老代(即旧生代)
缺点
效率问题
标记和清除的效率都不高
空间问题
大量不连续的内存碎片,这样给大对象分配内存的时候可能会提前触发full gc。
2. 复制
适用场合
存活对象较少的情况下比较高效
适用于年轻代(即新生代):基本上98%的对象是”朝生夕死”的,存活下来的会很少
存活对象较少的情况下比较高效
缺点
需要一块儿空的内存空间
需要复制移动对象
3 标记-整理
适用场合
用于年老代(即旧生代)
优点
不会产生内存碎片
缺点
需要移动对象,若对象非常多而且标记回收后的内存非常不完整,可能移动这个动作也会耗费一定时间
扫描了整个空间两次(第一次:标记存活对象;第二次:清除没有标记的对象)
4. 分代收集算法
从内存回收的角度来看,所以Java堆中还可以细分
新生代
Eden区
Survivor From
上一次GC的幸存者,作为这一次GC的被扫描者。
Survivor To
保留了一次MinorGC过程中的幸存者。
MinorGC采用复制算法
Minor GC触发条件
当Eden区满时
老年代
MajorGC(Full gc)采用标记—清除算法
触发条件
主要存放应用程序中生命周期长的内存对象
元空间(永久代)
新生代晋升老年代(对象内存分配和回收策略)
流程图
1.对象栈上分配
逃逸分析
栈上分配依赖于逃逸分析和标量替换
2.对象分配分配TLAB(Thread Local Allocation Buffer 线程本地分配缓存区)
栈上分配
逃逸分析
指针链撞
cos同步
3.对象优先分配在Eden
-XX:SurivorRatio=8 新生代Eden区域与Survivor区域的容量比值,默认为8,代表Eden: Suvivor= 8: 1。
-Xms20M 设置堆内存的初始值
-Xmx 设置堆内存的最大值
-Xmn 设置新生代的大小
-XX:+PrintSCDetails
大量的对象被分配在eden区,eden区满了后会触发minor gc,可能会有99%以上的对象成为垃圾被回收掉,剩余存活的对象会被挪到为空的那块survivor区
4.大对象直接进入老年代
-XX:PretenureSizeThreshold=3145728 3M
这个参数只在 Serial 和ParNew两个收集器下有效。
4.长期存活的对象进入老年代
age
-XX:MaxTenuringThreshold=15
5.动态对象年龄判定
相同年龄所有对象的大小总和>Survivor空间的一半
直接晋级,不需要判定MaxTenuringThreshold
6.空间分配担保
Minor GC 之前检查 老年代最大可用连续空间是否>新生代所有对象总空间
大于
Minor GC
不大于
老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小
大于
Minor GC
不大于
Full GC
-XX:+HandlePromotionFailure(16Update 24之后不生效)
允许担保失败
大于
Minor GC
不大于
Full GC
不允许担保失败
Full GC
流程图
4. 判断对象是否需要回收
引用计数法
优点
实现简单,判定效率高
缺点
循环引用
可达性分析算法
GC Roots→引用链
引用
强引用
引用在,不回收
软引用
SoftReference
OOM前,把这些对象回收
如果仍OOM→抛出异常
弱引用
WeakReference
下一次GC则清除
虚引用
PhantomReference
回收时→系统通知
5.Minor Gc和Full GC有什么不同呢
6.如何判断⼀个类是⽆⽤的类
5.垃圾收集器
1. Serial收集器
单线程,简单高效,历史悠久
它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
Client模式
新⽣代采⽤复制算法,⽼年代采⽤标记-整理算法。
2. Serial Old收集器
3. ParNew收集器
ParNew收集器就是Serial收集器的多线程版本
目前只有它能与CMS收集器配合工作
多线程,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作
多核CPU下对资源利用率会更高
新⽣代采⽤复制算法,⽼年代采⽤标记-整理算法
4. Parallel Scavenge收集器
Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量
新⽣代采⽤复制算法,⽼年代采⽤标记-整理算法。
5. Parallel Old收集器
使⽤多线程和“标记-整理”算法
6. CMS收集器
目标
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
回收算法
标记—清除
特点
CMS仅作用于老年代
并发收集、低停顿
CMS收集器的内存回收过程是与用户线程一起并发执行的
工作流程
初始标记: 暂停所有的其他线程,并记录下直接与root相连的对象,速度很快 ;
并发标记: 同时开启GC和⽤户线程,⽤⼀个闭包结构去记录可达对象。但在这个阶段结束,这
个闭包结构并不能保证包含当前所有的可达对象。因为⽤户线程可能会不断的更新引⽤域,所以
GC线程⽆法保证可达性分析的实时性。所以这个算法⾥会跟踪记录这些发⽣引⽤更新的地⽅。
个闭包结构并不能保证包含当前所有的可达对象。因为⽤户线程可能会不断的更新引⽤域,所以
GC线程⽆法保证可达性分析的实时性。所以这个算法⾥会跟踪记录这些发⽣引⽤更新的地⽅。
重新标记: 重新标记阶段就是为了修正并发标记期间因为⽤户程序继续运⾏⽽导致标记产⽣变
动的那⼀部分对象的标记记录,这个阶段的停顿时间⼀般会⽐初始标记阶段的时间稍⻓,远远⽐
并发标记阶段时间短
动的那⼀部分对象的标记记录,这个阶段的停顿时间⼀般会⽐初始标记阶段的时间稍⻓,远远⽐
并发标记阶段时间短
并发清除: 开启⽤户线程,同时GC线程开始对为标记的区域做清扫。
缺点
对CPU资源敏感;
⽆法处理浮动垃圾;
它使⽤的回收算法-“标记-清除”算法会导致收集结束时会有⼤量空间碎⽚产⽣。
7. G1收集器
图片
分区概念
分区 Region
卡片 Card
堆 Heap
特点
1.并行与并发
G1能充分利用多CPU、多核的硬件优势,来缩短Stop-The-World停顿时间
2.分代收集
和其他收集器相同,分代概念依然保留。G1收集器不需要其他收集器的配合就可以管理整个堆,可以根据不同的方式去处理新创建的对象、存活了一段时间的对象和熬过多次GC的对象。
3.空间整合
不同于CMS的标记-清理,G1采用的是标记-整理的方式来处理碎片化的空间。这种方式意味着G1收集器运作期间不会产生内存空间碎片,收集后提供规整的可用空间
4.可预测的停顿
G1相对于CMS另外一个更大的优势,就是可以设置可预测的停顿模型,能够使开发者明确指定在长度为M毫秒的时间片段内,消耗在垃圾收集器上的时间不能超过M毫秒。
G1提供了三种模式的垃圾回收
Minor GC
Mixed GC
Full GC
G1收集器的大概的工作过程
G1和CMS的比较
判断是否需要使用G1收集器
如何开启需要的垃圾收集器
8. jdk7、8、9默认垃圾回收器
jdk7
jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk8
jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk9
jdk1.9 默认垃圾收集器G1
9.作用的内存分区
理解吞吐量和停顿时间
停顿时间->垃圾收集器 进行 垃圾回收终端应用执行响应的时间
吞吐量->运行用户代码时间/(运行用户代码时间+垃圾收集时间)
吞吐量->运行用户代码时间/(运行用户代码时间+垃圾收集时间)
如何选择合适的垃圾收集器
6. 什么时间节点回收
安全点
方法调用
循环跳转
异常跳转
抢先式中断
先暂停,没在安全点就继续跑
主动式中断
设置GC标志
看到标志就停
安全域
GC ROOTS枚举效率
7.性能优化
1. GC相关的常用参数
Xmx: 设置堆内存的最大值。
-Xms: 设置堆内存的初始值。
-Xmn: 设置新生代的大小。
-Xss: 设置栈的大小。
打印所有XX参数及值
java -client -XX:+PrintFlagsFinal
-XX:+PrintCommandLineFlags
2. 日志
子主题
Full GC
3.JVM监控工具
JDK命令行
jps查看java进程
-l:输出主类的全名,如果进程执行的是 JAR 包,则输出 JAR 路径
-v:查看虚拟机启动时显式指定的JVM参数列表
未被显示指定的可通过 jinfo -flag 查看
jstat查看虚拟机性能统计信息
查看垃圾收集信息
jstat -gc PID 1000 10
-class:监视类加载、卸载数量、总空间以及类装载所耗费的时间
jstat -class PID 1000 10
查看某个java进程的类装载信息,每1000毫秒输出一次,共输出10 次
-gcutil:监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gcnew:监视新生代的垃圾收集情况
-gcold:监视老年代的垃圾收集情况
示例
jstat -gc 2764 250 20
每250毫秒查询一次进程2764垃圾收集状况,一共查询20次
jstat -gcutil 2764
查看2764进程各分区占比以及Minor GC和Full GC发生的次数和耗时
jinfo实时查看和调整JVM配置参数
查看某个java进程的name属性的值
jinfo -flag <name> PID
jinfo -flag MaxMetaspaceSize 18348
调整JVM参数
布尔类型的JVM参数
jinfo -flag [+|-]<name> PID
数字/字符串类型的JVM参数
jinfo -flag <name>=<value> PID
jmap生成堆转储快照
用于生成堆转储快照(一般称为heap dump或dump文件)还可以查询finalize执行队列、
Java堆和方法区的详细信息,如空间使用率、当前用的是哪种收集器等
Java堆和方法区的详细信息,如空间使用率、当前用的是哪种收集器等
jmap -dump
生成Java堆转储快照
dump出堆内存相关信息
jmap -dump:format=b,file=heap.hprof PID
如何在发生堆内存溢出的时候,能自动dump出该文件
jmap -heap PID
显示Java堆详细信息,如使用哪种回收器、参数配置、分代状况等
jmap -histo:live PID
显示堆中对象统计信息,包括类、实例数量、合计容量
jhat:堆转储快照分析工具
jhat命令与jmap搭配使用,来分析jmap生成的堆转储快照
jstack:Java堆栈跟踪工具
用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者 javacore文件)
jstack -l PID查看线程堆栈
解决死锁
1.找到进程中执行最高的线程号
通过top -Hp 48489可以查看该进程下各个线程的cpu使用情况
2.用jstack pid (进程号)导出线程的 dump日志
方法一:jstack 48489;
方法二:jstack -l <pid> >jvm_listlocks.txt
方法二:jstack -l <pid> >jvm_listlocks.txt
3.由于jstack.log文件记录的线程ID是16进制,需要将top命令展示的线程号转换为16进制。
把线程号转 16 进制 printf “%x \n” 40437
把线程号转 16 进制 printf “%x \n” 40437
4.到刚刚导出的 jvm_listlocks.txt 里面检索定位到定位到问题
扩展
getAllStackTraces()
可视化故障处理工具
JConsole
一款基于JMX(Java Manage-ment Extensions)的可视化监视、管理工具
启动JConsole后,会自动搜索本机运行的所有JVM进程,相当于可视化的jps命令
“内存”页签的作用相当于可视化的jstat命令,用于监视被收集器管理的虚拟机内存的变化趋势
“线程”页签的功能相当于可视化的jstack命令,用于分析线程停顿的原因,比如死循环,锁等待
Java VisualVM
功能最强大的运行监视和故障处理程序之一,曾经是Oracle官方主力发展的虚拟机故障处理工具
它除了常规的运行监视、故障处理外,还将提供其他方面的能力,譬如性能分析(Profiling)
优势:对应用程序实际性能的影响也较小,使得它可以直接应用在生产环境中
jps、jinfo、jstat、jstack、jmap、jhat等多种功能于一体
在Profiler页签中,VisualVM提供了程序运行期间方法级的处理器执行时间分析以及内存分析(生产不用)
BTrace动态日志跟踪插件
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,目的是定位线程
出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等
出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等
JMC
Java Mission Control:可持续在线的监控工具,可用于生产环境
JHSDB
一款基于服务性代理(Serviceability Agent,SA)实现的进程外调试工具
MAT
Java堆分析器,用于查找内存泄漏
GC日志分析工具
在线工具
https://gceasy.io
可以比较不同的垃圾收集器的吞吐量和停顿时间
ArtThas
阿里巴巴JVM调优工具
GCViewer
JVM调优的在线网站
Aliabba jvmGenerate: 是一个提供 JVM 参数调优分析,JVM优化工具集,快速生成JVM优化配置,常见场景配置示例的工具网站。
PerfMa
XXFox (Java虚拟机参数分析)
XSheepdog (Java线程Dump分析)
XElephant (Java内存Dump分析)
Thread dump分析网站
Fastt hread
Fastt hread: 一个在线的 Thread dump分析网站,能帮助我们判断 CPU 峰值、死锁、内存异常、应用反应迟钝、响应时间变长和其他系统问题。
heaphero
堆Dump可视化分析
jvmmemory
可视化界面在线生成JVM参数
4.故障定位
CPU
CPU 占用过高
先用 top 显示进程列表,找到占用率最高的 PID
再使用 top -Hp pid 找到占用最高的线程 tid
printf '%x\n' tid 将线程ID转换为16进制 (小写)
最后使用 jstack pid | grep tid -A60
频繁上下文切换
vmstat 2 3
每隔2秒打印一次CPU信息,共打印3次
cs:表示上下文切换次数(context switch)
pidstat -w pid
针对 pid 进行上下文切换监控
cswch/s:每秒自愿上下文切换(进程无法获取到可供执行的资源从而自愿发生上下文切换)
nvcswch/s:每秒非自愿上下文切换(进程时间片用完、被高优先级进程抢走、系统中断等发生的非自愿的场景)
内存
内存溢出
栈内存溢出
StackOverflowError
StackOverflowError
原因:线程请求栈的深度超过当前Java虚拟机栈的最大深度(默认大小是1M,1024KB)
代码举例
解决:检测是否有无穷递归、死循环,如果不是bug,可以通过调整虚拟机栈的大小来解决(-Xss2m)
堆内存溢出
OutOfMemory
OutOfMemory
原因:堆内存被用光,或者内存泄漏堆积导致
OOM
对象太多(Java heap space)
修复内存泄露,或使用 -Xmx 增加堆内存大小
代码举例
GC回收超时(GC overhead limit exceeded)
使用 -XX:-UseGCOverheadLimit 取消 GC 开销限制
本地内存不足(Direct buffer memory)
打印的堆栈跟踪信息,使用操作系统本地工具进行诊断
线程太多(unable to create new native thread)
减少虚拟机栈的大小或增大虚拟机占用比例
元空间内存不足(Metaspace)
使用-XX: MaxMetaSpaceSize 增加 metaspace 大小
内存泄漏
程序在申请内存后,无法释放已申请的内存空间
导致频繁 GC
jstat -gc pid 1000
每秒打印一次GC详细信息(C:容量|U:已使用)(E:Eden|O:Old|M:MetaSpace)
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
jstat -gcutil 1000 3
查看最近3次GC空间占比
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
使用 jmap 生成 堆转储 快照文件 jmap -histo:live pid
通过 (Thread dump分析工具)找出是哪块代码
查看线程信息
top -H -p pid
左上角显示Threads: 28 total,下面显示详细的线程信息
线程数
pstree -p 8379 | wc -l
ls /proc/8379/task | wc -l
ps hH p 8379 | wc -l
5.调优流程
调优阶段
上线前:根据需求(支撑多少QPS)进行JVM规划和预估调优(几台机器,多大内存,堆内存划分)
上线初期:根据日志优化JVM运行环境(解决慢、卡顿问题)
上线后期:解决JVM运行过程中出现的各种问题(OOM,逃逸分析,频繁 full gc)
调优指标
停顿时间
垃圾收集器做垃圾回收中断应用执行的时间
-XX:MaxGCPauseMillis:停顿时间(建议)
GC会尝试各种手段达到这个时间,比如减小年轻代
GC时间比例
GC时间占用程序运行时间的百分比:1/(1+n)
-XX:GCTimeRatio = n(默认值99)即 1% 时间用于垃圾收集
例如将 n=19 则垃圾收集时间为1/(1+19) 即 5% 时间用于垃圾收集
吞吐量
吞吐量=应用程序时间/(应用程序时间+垃圾收集时间) 即 1-1/(1+n)
调优参数
标准参数,-开头
通过 java 命令查看
常用参数
java -version
java -help
非标准参数
-X开头
通过 java -X more 查看
常用参数
-Xms200m -Xmx200m:最小堆和最大堆
-Xmn60m:新生代
-Xss1m:栈空间大小
扩展:为什么最小堆和最大堆设置一样大?
防止内存震荡(否则JVM会将堆内存进行扩容和缩容)
扩展和回缩需要大量的计算,影响程序的执行效率
-XX开头
通过 java -XX:+PrintFlagsFinal -version | more 命令查看
常用参数
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
GC调优
Parallel常用参数
-XX:SurvivorRatio:调整eden和surviovor区域的大小
-XX:PreTenureSizeThreshold:大对象到底多大
-XX:MaxTenuringThreshold:设置的是年龄阈值,默认15(对象被复制的次数)
-XX:+ParallelGCThreads:并行收集器的线程数,一般设置为和CPU核数相同(同样适用于CMS)
-XX:+UseAdaptiveSizePolicy:自动选择各区大小比例
CMS常用参数
-XX:+UseConcMarkSweepGC:启用CMS收集器
-XX:ParallelCMSThreads:CMS线程数量
-XX:CMSInitiatingOccupancyFraction
使用多少比例的老年代后开始CMS收集,默认是68%(近似值)
如果频繁发生SerialOld卡顿,应该调小(频繁CMS回收)
如果频繁发生SerialOld卡顿,应该调小(频繁CMS回收)
-XX:+UseCMSCompactAtFullCollection:在FGC时进行压缩
-XX:+CMSClassUnloadingEnabled
默认情况下GC是不回收PermGen的空间的(其名字也能反映这点)
这个选项就是启用清除PermGen的功能,删除不用的classes
这个选项就是启用清除PermGen的功能,删除不用的classes
-XX:CMSInitiatingPermOccupancyFraction
达到什么比例时进行Perm回收
-XX:GCTimeRatio
设置GC时间占用程序运行时间的百分比
-XX:MaxGCPauseMillis
停顿时间(建议)GC会尝试各种手段达到这个时间,比如减小年轻代
G1常用参数
-XX:+UseG1GC
-XX:MaxGCPauseMillis
建议值,G1会尝试调整Young区的块数来达到这个值
-XX:+GCPauseIntervalMillis
GC的间隔时间
-XX:+G1HeapRegionSize
分区大小,建议逐渐增大该值
-XX:G1NewSizePercent
新生代最小比例,默认为5%
-XX:G1MaxNewSizePercent
新生代最大比例,默认为60%
-XX:GCTimeRatio
GC时间建议比例,G1回根据这个值调整堆空间
-XX:ConcGCThreads
线程数量
-XX:InitiatingHeapOccupancyPercent
启动G1堆空间占用比例
日均百万交易系统
JVM堆栈大小设置?
JVM 调优,让其几乎不发生 Full GC?
G1调优与最佳指南
调优
是否选用G1垃圾收集器的判断依据
(1)50%以上的堆被存活对象占用 (2)对象分配和晋升的速度变化非常大 (3)垃圾回收时间比较长
(1)使用G1GC垃圾收集器: -XX:+UseG1GC
(2)调整内存大小再获取gc日志分析
(3)调整最大停顿时间
(4)启动并发GC时堆内存占用百分比
最佳指南
(1)不要手动设置新生代和老年代的大小,只要设置整个堆的大小
(2)不断调优暂停时间目标
(3)使用-XX:ConcGCThreads=n来增加标记线程的数量
(4)MixedGC调优
(5)适当增加堆内存大小
0 条评论
下一页