首先一定要清楚:java应用造成cpu过高的主要原因
1:一般是线程一直处于可运行(Runnable)状态,通常这些线程在执行无阻塞操作、循环、正则或纯粹的计算等任务
2:另一个可能造成CPU高的原因是频繁GC,这个也是我遇到比较多的,有如下情况
2-1:堆内存不足:
如果JVM堆内存设置得太小,应用程序可能需要频繁地创建新对象,导致堆内存很快被填满,从而触发GC。
2-2:对象生命周期短:
创建了很多生命周期很短的对象,这些对象死后很快就会变成垃圾,增加了GC的压力。
2-3:内存泄漏:
代码中存在内存泄漏,即长时间持有不再使用的对象引用,导致这些对象不能被回收,随着时间的推移,内存泄漏会导致堆内存中积累大量垃圾。
2-4:大对象分配:
频繁分配大对象(如大数组或大字符串)可能导致老年代内存很快被填满,触发Full GC。
2-5:不恰当的垃圾收集器选择:
使用了不合适的垃圾收集器,或者垃圾收集器的参数设置不当,可能不适合应用程序的特定需求。
2-6:新生代与老年代比例不当:
新生代(Young Generation)与老年代(Old Generation)的比例设置不当,可能导致新生代频繁GC或者老年
2-7:代频繁Full GC。
2-8:线程数量过多:
创建了大量线程,每个线程都有自己的栈和相关资源,过多的线程可能导致频繁的GC。
2-9:静态
像ArrayList、HashMap这样的静态集合类,如果不断添加元素而不及时清理,会占用越来越多的内存,导致频繁GC。
2-10:缓存策略不当:
缓存数据没有合理设置过期策略或清理机制,导致缓存数据长期占用内存。
2-11:持久代(PermGen)空间不足:
在Java 8之前,持久代(PermGen)用于存储类的元数据,如果加载的类太多,或者有大量字符串常量,可能会导致PermGen空间不足,触发GC。
2-12:JVM参数设置不当:
如-Xmn(设置新生代大小)、-XX:SurvivorRatio(设置Eden区和Survivor区的比例)等参数设置不当,可能导致频繁GC。
要解决频繁GC的问题,可以采取以下措施:
监控和分析GC日志,使用工具如VisualVM、JConsole、MAT等。
优化代码,减少内存泄漏和不必要的对象创建。
调整JVM参数,合理设置堆内存大小和垃圾收集器。
优化数据结构和算法,减少内存消耗。
实施有效的缓存策略和资源管理。
1:使用top命令查看那个进程占用过高
2:查看进程中线程使用情况,使用命令 top -H -p 查看如下图:
#-H:所有线程占用资源情况。
#-p<进程号>:指定进程;
top -H -p 16387
3:查看进程中的线程快照,先将现场转成16进制
3-1:查看线程23696,先转16进制
[root@localhost ~]# printf "%x\n" 23696
5c90
3-2:通过jstack 命令查看线程23696的快照(docker内部如果使用是精简的jdk可能没有jstack这个命令)
[root@localhost ~]# jstack 16387 |grep "5c90" -A 30
"System Clock" #65 daemon prio=5 os_prio=0 tid=0x00007f8668545000 nid=0x5c90 runnable [0x00007f86fc9e4000]java.lang.Thread.State: TIMED_WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000006cf3fa670> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)"lettuce-eventExecutorLoop-1-8" #64 daemon prio=5 os_prio=0 tid=0x00007f866808e800 nid=0x5bc5 waiting on condition [0x00007f86fd0e5000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000006c9594648> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)at io.netty.util.concurrent.SingleThreadEventExecutor.takeTask(SingleThreadEventExecutor.java:243)at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:64)at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)at java.lang.Thread.run(Thread.java:748)"lettuce-eventExecutorLoop-1-7" #63 daemon prio=5 os_prio=0 tid=0x00007f865c079800 nid=0x5bb2 waiting on condition [0x00007f86fd1e6000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000006c9579898> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
[root@localhost ~]#