一:内存溢出
分类
- 堆溢出
-Xmx45M -Xms45M
@GetMapping("/heap")
public void heap() {
List<UserEntity> userEntities = new ArrayList<>();
System.out.println("start......");
while (true) {
UserEntity userEntity = new UserEntity(1, "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a");
userEntities.add(userEntity);
}
}
start......
2020-08-20 11:04:14.711 ERROR 17980 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space] with root cause
java.lang.OutOfMemoryError: Java heap space
- 元空间溢出
同堆溢出,只需将new对象替换成new元空间元素即可(如new class)
线上导出内存映像文件
- 自动导出
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to ./\java_pid22392.hprof ...
Heap dump file created [53114704 bytes in 0.184 secs]
- 手动jmap
jmap -dump:format=b,file=pid22392.hprof 22392
利用工具进行分析
eclipse:Jmat
idea:JProfiler(具体安装步骤https://blog.csdn.net/qq_22194659/article/details/83829891)
可以看出启动后内存占用20M左右,第10秒后用户来了请求,持续创建对象,最大到Xmx45M,第45秒时最终因为内存溢出二程序关闭。
查看recorded object
发现userEntity 对象有4万多,因此定位到了内存溢出的原因。
二:CPU过高
模拟CPU过高
首先我们写一个函数,让他一直死循环
@GetMapping("/cpu")
public void cpu() {
while (true) {
}
}
把他发布到Linux系统服务器中,请求三次"ip:port/cpu”路径
利用top指令
如图PID为4500进程占用99%cpu
top -H -p5040查看进程的每一个线程
将三个线程ID转为16进制
[root@iZuf60tktze54jh7ucqlcrZ /]# printf "%x\n" 5056
13c0
[root@iZuf60tktze54jh7ucqlcrZ /]# printf "%x\n" 5057
13c1
[root@iZuf60tktze54jh7ucqlcrZ /]# printf "%x\n" 5058
13c2
利用jstack导出信息
jstack 22536> 22536.txt
在22536.txt里面寻找16进制的线程Id
"http-nio-8888-exec-1" #18 daemon prio=5 os_prio=0 tid=0x000000002b60b000 nid=0x5540 runnable [0x000000002e44c000]
java.lang.Thread.State: RUNNABLE
at com.example.demo.UserController.cpu(UserController.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
......
很容易定位到UserController.java的第33行 while (true) {
出现了问题
三:死锁
写一个死锁
Object object1 = new Object();
Object object2 = new Object();
@GetMapping("/deadLock")
public void deadLock() {
new Thread(() -> {
synchronized (object1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object2) {
System.out.println("1");
}
}
}).start();
new Thread(() -> {
synchronized (object2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
System.out.println("2");
}
}
}).start();
}
jstack pid> pid.txt
四:Jinfo与Jstat使用
jps
查看进程ID:20832
jinfo查看运行时参数
- 查看最大堆大小
$ jinfo -flag MaxHeapSize 20832
-XX:MaxHeapSize=8575254528
- 查看用的啥垃圾回收器
$ jinfo -flag UseConcMarkSweepGC 20832
-XX:-UseConcMarkSweepGC
$ jinfo -flag UseG1GC 20832
-XX:-UseG1GC
$ jinfo -flag UseParallelGC 20832
-XX:+UseParallelGC
jstat查看jvm统计信息
查看类加载信息(-class),垃圾收集(-gc),JIT编译(-compile)
$ jstat -class 20832 1000 10
Loaded Bytes Unloaded Bytes Time
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
10620 19304.1 0 0.0 4.69
$ jstat -gc 20832 1000 3
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
12800.0 11264.0 0.0 11261.7 757248.0 688304.8 256000.0 19291.1 45008.0 43021.8 5888.0 5547.1 9 0.040 2 0.103 0.143
12800.0 11264.0 0.0 11261.7 757248.0 688304.8 256000.0 19291.1 45008.0 43021.8 5888.0 5547.1 9 0.040 2 0.103 0.143
12800.0 11264.0 0.0 11261.7 757248.0 688304.8 256000.0 19291.1 45008.0 43021.8 5888.0 5547.1 9 0.040 2 0.103 0.143
$ jstat -compiler 20832 1000 3
Compiled Failed Invalid Time FailedType FailedMethod
6961 1 0 18.24 1 org/aspectj/weaver/ResolvedType lookupResolvedMember
6961 1 0 18.24 1 org/aspectj/weaver/ResolvedType lookupResolvedMember
6961 1 0 18.24 1 org/aspectj/weaver/ResolvedType lookupResolvedMember
Compiled :任务(方法编译成本地方法)
Failed :失败
五:开发中的优化方法
- 尽量重用对象,比如不能再for循环中一直new对象
- 容器类一定要指定初始大小
- 使用适合的容器类如ArrayList随机遍历,LinkList添加删除
- 集合遍历尽量减少重复计算,如不应该在循环体中出现collection.size()
- 遍历map用entry
- 尽量使用Native方法,如大数组拷贝用System.arraycopy
- 尽量使用基本类型而不是包装类型
- 不能手动System.gc()
- 及时删除过期对象
- 尽量使用延时加载
- 少使用反射
- 不要忘记关闭资源
- 尽量使用资源池
- 慎用异常
- 少用正则
更多前沿技术,面试技巧,内推信息请扫码关注公众号“云计算平台技术”