JVM笔记
-
jvm 配置参数
-
-verbose:gc -XX:+PrintGCDetails 打印GC回收的信息
-
-XX:ParallelGCThreads=4 (PreNew垃圾回收)垃圾回收的线程数(推荐为CPU的核数作为值,过多线程会导致上下文切换)
-
-XX:MaxGCPauseMills GC回收停顿时间毫秒数(数值太小会发生频繁GC)
-
-XX:GCTimeRation GC吞吐率(默认99%)即用户运行代码,1%为垃圾收集器处理时间
-
-XX:+UseSerialGC :采用Serial收集器,单线程原始的
-
-XX:PretenureSizeThreshold=3145728 大对象超过多少字节直接分配在Old老年代内存块
-
-XX:-/+DoEscapeAnalysis 关闭/开启逃逸分析
-
-XX:+HeapDumpOnOutOfMemoryError 开启发生内存溢出时生成溢出时的堆内存块照
-
-XX:HeapDumpPath:{path} 将发生内存溢出的堆快照保存路径配合8使用
-
-XX:+DisableExplicitGC 禁止系统调用System.gc()方法导致频繁FullGC
-
-XX:SurvivorRatio=8 配置新生代eden区比例(默认是8剩下的是from 与 to 平分)
-
-XX:NewRatio=2 新生代与老年代占用比例(默认是2即老年代占2份,新生代占1份即1/3,如果修改为其他比如4即老年代占用4新生代占用1/5)
-
-XX:MaxTenuringThreshold=15 对象在新生代经过多少次交换会进入老年代(jdk8默认是15:0-15之间)即值会影响对象进入老年代进行Full GC次数
-
-XX:MetaspaceSize=512m 元空间大小(不在虚拟机中,受限于本地内存)(存放虚拟机加载类信息,常量池,静态变量,及时编译后的代码)
-
-XX:MaxMetaspaceSize=512m
-
常用配置参数
-
-Xms 初始大小内存,默认物理内存1/64(线上一般和-Xmx值一直)
-
-Xmx 最大分配内存,默认物理内存1/4
-
-Xss 单个线程栈的大小,一般默认512k-1024k(依赖于系统)
-
-Xmn 设置年轻代大小(很少调)
-
-XX:MetaspaceSize 元空间大小(不在虚拟机中,受限于本地内存)
-
-XX:+PrintGCDetails 打印GC回收详情
-
-XX:HeapDumpPath:{path} 将发生内存溢出的堆快照保存路径
JAVA堆内存划分
-
JAVA堆内存的分配可分为Old(老年代 2/3),Young(新生代)1/3(包含Eden 8/10,From 1/10,To 1/10)
-
新对象会优先在新生代的Eden分配,如果对象过大存放不了会分配给Old老年代
方法逃逸与栈上分配
- 方法逃逸
jdk1.8默认开启逃逸分析,将逃逸的对象进行栈上分配空间,关闭则会分配在堆空间(会发生回收现象)
参数: -XX:+DoEscapeAnalysis(开启) -XX:-DoEscapeAnalysis(关闭)
public static Object obj;
public void t1(){
obj = new Object();//发送方法逃逸
}
public Object t2(){
return new Object();//发生方法逃逸
}
public static void type(){
byte[] b = new byte[2];
b[0] = 1;
}
以下代码测试开启逃逸分析与关闭的效果
关闭的时候执行时间为 112毫秒 开启的时候为4毫秒
public static void type(){
byte[] b = new byte[2];
b[0] = 1;
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i=0;i<10000000;i++){
type();
}
long end = System.currentTimeMillis();
System.out.println(end-start);
}
JVM 分析工具
- jstat:
jstat -gc pid 500 10 每500毫秒打印10次进程pid的内存信息(包含新生代/老年代使用率,GC次数。。。)
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
1344.0 1344.0 0.0 910.4 11264.0 9228.2 27844.0 27157.0 55856.0 53078.4 7728.0 7191.0 269 0.811 3 0.137 0.948
-
jinfo:打印JMV的基本配置参数信息
-
jmap:生产堆内存快照(主要用于分析)
jamp -heap pid 打印进程堆
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 12910592 (12.3125MB)
used = 10875504 (10.371688842773438MB)
free = 2035088 (1.9408111572265625MB)
84.23706674333756% used
Eden Space:
capacity = 11534336 (11.0MB)
used = 9943264 (9.482635498046875MB)
free = 1591072 (1.517364501953125MB)
86.2057772549716% used
From Space:
capacity = 1376256 (1.3125MB)
used = 932240 (0.8890533447265625MB)
free = 444016 (0.4234466552734375MB)
67.73739769345238% used
To Space:
capacity = 1376256 (1.3125MB)
used = 0 (0.0MB)
free = 1376256 (1.3125MB)
0.0% used
tenured generation:
capacity = 28512256 (27.19140625MB)
used = 27808768 (26.5205078125MB)
free = 703488 (0.6708984375MB)
97.5326820859072% used
jmap -histo pid 打印java对象堆直方图
num #instances #bytes class name
----------------------------------------------
1: 102023 12661296 [C
2: 9508 2767192 [I
3: 26516 2333408 java.lang.reflect.Method
4: 85546 2053104 java.lang.String
5: 6023 1805944 [B
6: 41271 1320672 java.util.concurrent.ConcurrentHashMap$Node
7: 11764 1296224 java.lang.Class
8: 29495 1179800 java.util.LinkedHashMap$Entry
9: 11658 900848 [Ljava.util.HashMap$Node;
10: 14174 791400 [Ljava.lang.Object;
11: 14011 784616 java.util.LinkedHashMap
12: 10090 726480 java.lang.reflect.Field
13: 24272 533400 [Ljava.lang.Class;
jmap -dump:live,format=b,file=heap.bin pid 导出JAVA进程内存快照
分析线程(检查死锁)
-
ps -mp pid -o THREAD,tid,time 查询进程的运行线程
-
获取执行时间较长的线程tid,将之转为16进制 printf “%x\n” tid
-
jstack pid |grep tid(转为16进制后的值) -A 30 打印线程信息
-
jstack -m 或者使用jconsole和visualvm检查是否有死锁
jvm分析工具
-
使用jdk自带工具 jconsole命令
可以分析本地与远程的堆栈信息可视化窗口(远程)java启动时需要带一下参数
-Djava.rmi.server.hostname=192.168.226.128 服务器ip
-Dcom.sun.management.jmxremote.port=9999 远程jmx管理界面的
-Dcom.sun.management.jmxremote.ssl=false 关闭ssl验证
-Dcom.sun.management.jmxremote.authenticate=false -
visualvm工具 jdk自带,idea可以下载插件
FullGC问题与解决方案
-
出现FullGC原因
-
代码调用System.gc();方法导致 可以使用-XX:+DisableExplicitGC 禁止系统调用
-
老年代空间不足
-
空间分配担保失败:
-
解决方案:
合理控制 JVM -Xmx 参数的大小 然后集群部署项目,值太大会导致FullGC的时间过长
-
-
堆内存泄漏问题:
-
出现OOM或者Full GC,heap经常达到Xmx
-
Full GC出现的频率大概一天1到2两次
-
解决方案: jmap dump 本地使用jhat(jdk自带)或者jconsole和visualvm分析
-
打印JDK默认JVM参数
-
java -XX:+PrintFlagsInitial
-
java -XX:+PrintFlagsFinal -version 打印里面有修改的前面有带冒号等号:=
-
java -XX:+PrintCommandLineFlags -version 打印简化的初始化参数
JVM GC日志参数分析
[GC (Allocation Failure) [PSYoungGen: 1821K->488K(2560K)] 1821K->680K(9728K), 0.0011150 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 644K->626K(7168K)] 644K->626K(9728K), [Metaspace: 3437K->3437K(1056768K)], 0.0076044 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
-
参数解释([名称 GC前内存占用大小->GC后内存占用大小]该区总内存大小)
-
[PSYoungGen: 1821K->488K(2560K)]:年轻代GC回收,gc前新生代占用内存大小->gc后新生代占用内存大小(新生代总共配置的内存大小)
-
1821K->680K(9728K):gc前JVM堆占用内存->gc后JVM堆占用内存大小(JVM配置的堆内存大小)
-
[Times: user=0.00 sys=0.00, real=0.00 secs]:gc用户耗时大小,系统耗时大小,实际耗时大小
-
强引用,软引用,弱引用,虚引用
- 强引用(即使发生OOM也不会回收内存)
Object o1 = new Object();
- 软引用(内存足够不会回收,不够则回收)
SoftReference<Object> s1 = new SoftReference<Object>(new Object());
- 弱引用(只要发生gc就会回收)
WeakReference<Object> w1 = new WeakReference<Object>(new Object());
- 软,弱引用使用场景
- 需要加载大量本地图片时,可以使用,内存不足时JVM会自动回收这些缓存的图片地址有效避免OOM
Map<String,SoftReference<Bitmap>> map = new HashMap<String,SoftReference<Bitmap>>();
-
WeakHashMap 弱引用Map,发生gc会被回收,可以做缓存
-
虚引用,无论何时都可被回收,需要配合引用队列使用,可在对象销毁之后作出一些处理动作
ReferenceQueue<Object> r1 = new ReferenceQueue<>();
PhantomReference<Object> p1 = new PhantomReference<>(new Object(),r1);
垃圾收集算法
-
标记-清除算法
该算法分为标记与清除两个阶段- 标记所有需要回收的对象
- 回收所有标记完成的对象
缺点:
- 效率问题:标记和清除两个过程效率都不高
- 空间问题:标记清除之后会产生大量不连续内存碎片,空间碎片太多可能会导致以后再程序
运行过程中需要分配比较大的对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集动作
-
复制算法
优点:运行高效,分配内存不用考虑内存碎片问题
缺点:将内存使用空间降低了一半,因为分配时需要将内存划分为大小相等两块 -
标记-整理算法
跟标记-清除算法一样,不一样的是不直接将可回收的对象进行清理,而已让所有存活的对象向一端移动,
然后直接清理掉端边界以外的内存 -
分代收集
把java堆分为新生代和老年代,根据不同情况采用不同算法回收
垃圾回收器
-
Serial(-XX:+UseSerialGC): 串行回收 为单线程环境设计会暂停所用用户线程
-
PreNew(-XX:+UseParNewGC): 主要采用多线程回收(新生代)内存配合
-XX:ParallelGCThreads=4(推荐使用CPU核数作为值)设置回收的线程数
-
GMS(-XX:+UseConcMarkSweepGC): (速度快)采用并发(标记-清除)算法,不需要暂停用户线程,适用响应有要求场景(互联网公司)
-
是最短收集停顿时间收集器(垃圾收集器收集时会停顿用户线程)
-
清除步骤
初始化标记:标记GC Roots能直接关联的对象(会停顿用户线程)
并发标记:对堆中对象进行可达性分析,找出存活对象
重新标记:修正标记期间用户程序导致标记产生的变动标记(会停顿用户线程)
并发清除: -
缺点:
对CPU资源敏感:因为采用线程所有会占用CPU资源
无法清除浮动垃圾:并发清除是用户产生的新垃圾
标记清除会导致垃圾碎片
-
-
Parallel:并行回收 会暂停用户线程使用于科学计算/大数据处理
- Parallel Scavebge(-XX:+UseParallelGC): 多线程回收(新生代)内存,采用(复制算法)
该回收期所关注的不是垃圾收集用户线程的停顿时间,而是收集器的目标达到可控制的吞吐量(CPU用于运行用户代码与CPU总消耗时间比值,即吞吐量=运行用户代码/(用户代码运行时间+垃圾收集时间))
主要参数为:
-XX:MaxGCPauseMills GC回收停顿时间毫秒数(数值太小会发生频繁GC)-XX:GCTimeRation GC吞吐率(默认99%)即用户运行代码,1%为垃圾收集器处理时间- Parallel old(-XX:+UseParallelOldGC): 收集老年代内存,采用(标记整理)算法
- Parallel Scavebge(-XX:+UseParallelGC): 多线程回收(新生代)内存,采用(复制算法)
-
G1:采用(标记整理)算法 -XX:+UseG1GC
-
与GMS区别在与G1对空间的整合,G1采用将内存划分为一块一块区域,并发回收,停顿少(可以指定停顿时间),没有内存碎片,没有物理隔离只有逻辑分代
-
步骤
初始标记
并发标记
最终标记
并发清除 -
配合参数
-XX:G1HeapRegionSize=n 区域块大小,2的幂次方(1-32m),默认是2048块最大也是2048块即最大64G
-XX:MaxGCPauseMillis=n 最大GC停顿时间(毫秒)
-
GC选择

-
年轻代—老年代(选择新生代的算法会自动匹配老年代算法):
- Serial(-XX:+UseSerialGC)—Serial Old()
-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialGC
2. PreNew(-XX:+UseParNewGC)---CMS(-XX:+UseConcMarkSweepGC)
-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParNewGC -XX:+UseConcMarkSweepGC(这个不配置会使用Serial Old已被弃用)
3. Parallel Scavebge(-XX:+UseParallelGC)---Parallel old(-XX:+UseParallelOldGC)/Serial Old
-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParallelGC
4. G1(-XX:+UseG1GC)---G1(-XX:+UseG1GC)
-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseG1GC
-
多CPU需要最大吞吐量,如后台计算型应用采用
-XX:+UseParallelGC -
多CPU,追求快速响应停顿低,需要快速响应的互联网应用
-XX:+UseConcMarkSweepGC
配置
- 打印JVM初始化配置 java -XX:+PrintCommandLineFlags -version
JVM与Springboot配置
- java -server jvm参数 -jar jar/war包名称
本文深入探讨JVM配置参数,包括GC日志分析、垃圾回收算法与收集器选择,详解如何通过调整参数提升应用程序性能,减少Full GC,解决堆内存泄漏问题。

1201

被折叠的 条评论
为什么被折叠?



