-verbose:gc -XX:+PrintGCDetails -XX:+PrintHeapAtGC(详细的gc信息)
(例如: -Xloggc:C:\logs\gc.log)
-XX:-UseGCLogFileRotation
-XX:GCLogFileSize = 8M
(例如-Xms20M指定最小堆内存为20M)
(例如-Xms20M指定最大堆内存为20M)
(例如-Xmn10M指定新生代内存为10M)
(eden比S0,S1区比例为8:1:1)
初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。 -XX:MaxMetaspaceSize 最大空间,默认是没有限制的。
此参数只能在serial收集器和parnew收集器才有效
(比如 -XX:PretenureSizeThreshold=1M)
(比如 -XX:MaxTenuringThreshold=15 默认也是15次)
-XX:+HeapDumpOnOutOfMemoryError
该配置会把快照保存在用户目录或者tomcat目录下,也可以通过 -XX:HeapDumpPath=/tmp/heapdump.dump来显示指定路径
该标志首先是激活CMS收集器。默认HotSpot JVM使用的是并行收集器。
-XX:+CMSConcurrentMTEnabled
-XX:ConcGCThreads
标志-XX:ConcGCThreads=<value>(例如:-XX:ConcGCThreads=4)
-XX:CMSInitiatingOccupancyFraction=70 和 -XX:+UseCMSInitiatingOccupancyOnly
默认参数场景是:-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0。这意味着每次full gc(标记清除)后,都会压缩
-XX:+CMSScavengeBeforeRemark
1.178: [GC (Allocation Failure) [PSYoungGen: 32768K->2688K(37888K)] 32768K->2696K(123904K), 0.0048091 secs] [Times: user=0.05 sys=0.02, real=0.00 secs]
1.178: # 虚拟机启动以来的秒数
[GC (Allocation Failure)
[PSYoungGen: 32768K->2688K(37888K)] # gc类型:新生代gc前占用大小 -> 新生代gc后占用大小(新生代总容量)
32768K->2696K(123904K), # 堆空间gc前占用大小 -> 堆空间gc后占用大小(堆空间总容量)
0.0048091 secs #gc总耗时
] [
Times:
user=0.05 #用户态耗费时间
sys=0.02, #内核态耗费时间
real=0.00 secs #整个过程实际耗费时间
]
# user+sys是CPU时间,每个CPU core单独计算,所以这个时间可能会是real的好几倍。
7.740: [Full GC (Metadata GC Threshold) [PSYoungGen: 6612K->0K(333824K)] [ParOldGen: 10378K->15906K(95744K)] 16990K->15906K(429568K), [Metaspace: 34026K->34026K(1079296K)], 0.1300535 secs] [Times: user=0.38 sys=0.00, real=0.13 secs]
7.740: #虚拟机启动以来的秒数
[
Full GC (Metadata GC Threshold) #gc类型
[PSYoungGen: 6612K->0K(333824K)] # 新生代gc前占用大小 -> 新生代gc后占用大小(新生代总容量)
[ParOldGen: 10378K->15906K(95744K)] # 老年代代gc前占用大小 -> 老年代gc后占用大小(老年代总容量)
16990K->15906K(429568K), # 堆空间gc前占用大小 -> 堆空间gc后占用大小(堆空间总容量)
[Metaspace: 34026K->34026K(1079296K)], # 元空间gc前占用大小 -> 元空间gc后占用大小(元空间总容量)
0.1300535 secs #gc总耗时
]
[
Times:
user=0.05 #用户态耗费时间
sys=0.02, #内核态耗费时间
real=0.00 secs #整个过程实际耗费时间
]
# user+sys是CPU时间,每个CPU core单独计算,所以这个时间可能会是real的好几倍。
package com.kawa.xuduocloud.zuul; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @program: xuduocloud * @author: Brian Huang * @create: 2019-12-07 15 **/ @RestController public class JvmController { @GetMapping("/deadLock") public ResponseEntity<String> deadLock(){ Object lockA = new Object(); Object lockB = new Object(); new Thread(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); synchronized (lockA) { System.out.println(name + " got lockA, want LockB"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockB) { System.out.println(name + " got lockB"); System.out.println(name + ": say Hello!"); } } } }, "thread-lock-A").start(); new Thread(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); synchronized (lockB) { System.out.println(name + " got lockB, want LockA"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockA) { System.out.println(name + " got lockA"); System.out.println(name + ": say Hello!"); } } } }, "thread-lock-B").start(); return new ResponseEntity<>("deadLock", HttpStatus.OK); } }
我这边启动是XuduocloudZuulApplication这个项目
$ jstack 18640 > C:\\Users\\LiangHuang\\Desktop\\lock.txt
打开lock.txt文件,搜索关键字“deadlock”,可以很清晰的看到锁与等待锁的信息
Found one Java-level deadlock: ============================= "thread-lock-B": waiting to lock monitor 0x000000001e9975b8 (object 0x00000000e8cc87d8, a java.lang.Object), which is held by "thread-lock-A" "thread-lock-A": waiting to lock monitor 0x0000000017e26338 (object 0x00000000e8cc87c8, a java.lang.Object), which is held by "thread-lock-B" Java stack information for the threads listed above: =================================================== "thread-lock-B": at com.kawa.xuduocloud.zuul.JvmController$2.run(JvmController.java:55) - waiting to lock <0x00000000e8cc87d8> (a java.lang.Object) - locked <0x00000000e8cc87c8> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) "thread-lock-A": at com.kawa.xuduocloud.zuul.JvmController$1.run(JvmController.java:34) - waiting to lock <0x00000000e8cc87c8> (a java.lang.Object) - locked <0x00000000e8cc87d8> (a java.lang.Object) at java.lang.Thread.run(Thread.java:748) Found 1 deadlock.
其实定位线上死锁比较简单两个指令就可以可了 ==> jps+ jstack
4.1 来一个cpu100%代码
可以看到pid为7977java进程占用最高
可以看到tid为8072的子线程占用率最高
查找方式最将刚才tid从十进制转为16进制 8072 => 1f88
在日志文件搜索关键字 ‘1f88’ 查找nid包含这个就是对应cpu100%的日志信息 , 如下
生产环境cpu飙高三个指令就可以了 => top + ps + jstack
环境配置 -verbose:gc -XX:+PrintGCDetails -Xloggc:C:\Users\LiangHuang\Desktop\up\gc.log -XX:-UseGCLogFileRotation -XX:GCLogFileSize=5M -XX:HeapDumpPath=C:\Users\LiangHuang\Desktop\heapdump.dump -XX:+HeapDumpOnOutOfMemoryError
可以在oom时候生产快照,方便我们使用工具分析
jvisualvm.exe导入dump文件
可以看到异常的线程,打开Show Threads 详细信息,搜索关键字“http-nio-82-exec-1”
可以看到eden区和老年代 没有被回收,内存泄漏的导致不能被回收
jvisualvm.exe导入dump文件
-Xmx 堆内存最大值 -Xmx2g -Xms 堆内存最小值 -Xms2g -Xmn 新生代大小 默认时堆的1/3 -xss 线程栈空间大小 -Xss256k
线程共享 堆: new出来的对象放在堆中,对象可能会栈上分配(内存逃逸分析) 元空间/方法区:class对象,常量,静态变量,运行时常量池 内存独占 栈:栈内部由栈帧组成,先进后出,栈帧(局部变量表,操作数栈,动态链接,返回地址) PC寄存器(程序计数器):指向当前线程执行到多少行代码 本地方法栈: native修饰的方法
gc算法== 分代算法 复制算法 标记清除 标记压缩 引用计数 可达性分析法 gc收集器== young区 (Serial,ParNew,Parallel Scavenge) old区(SerialOld,ParallelOld,CMS) G1
局部变量 静态变量 本地方法栈 静态常量 static final
Serial:单线程收集 非单核服务器 stw比较长 Parnew: 多线程收集 多核线程比较快 PS: 可控吞吐量 (用户线程执行时间)/(用户线程执行时间+gc执行时间) CMS: 初始标记(标记和gc roots相关的对象 有swt), 并发标记(标记被初始标记的对象关联的对象 和用户线程一起执行), 重新标记(新生代可达引用到老年代的对象,刚进入老年代的对象 stw), 并发清除 (和用户线程一起执行,清除老年代没有被标记的对象)
minor gc新生代gc major gc老年代gc full gc= minor gc + major gc stw: stop the word 停止其他所有的用户线程
正常流程=== 经过15次ygc(复制算法)晋升到老年代 大对象直接进入到老年代 非正常===
动态年龄 (s区 50%以上对象年龄 > s区平均年龄则进阶老年代,如果老年代空间不足则发生full gc) 空间担保 (s0或s1放不下这些对象,会进行于此空间担保(老年代剩余空间大于历代s区进阶的平均值则担保成功))如果担保 失败则发生full gc 元空间/方法区不足也会发生full gc,但不会被垃圾收集器回收
对象不能被gc回收就会导致内存泄漏
jstack 发生gull gc后,新生代和老年代的占用情况,如果占用的空间没有降低则可以判断放生内存泄漏
如果fgc放生频率远远高于ygc则发生了内存泄漏
后台没写分页,大数据量,内存溢出报错后,对象会被回收,整个服务任然可用
内存泄漏导致的内存溢出,泄漏的对象不会被回收,知道我们的整个堆内存被占满,导致整个服务不可用
打印dump文件,分析快照,查找大对象
强引用:Object o = new Objetc(); gc不会回收强引用对象 软引用:SoftReference 对内存占满时就会这里面的对象(这个一般用来做缓存) 弱引用:WearkReference 只能存在下一次gc之前 (minor gc,major gc发生就会被回收) 虚引用:Object o = new Object(); o = null; 提醒gc来回收这个对象
原文:https://www.cnblogs.com/hlkawa/p/11965522.html