JAVA进程占用CPU很高,除了程序确实是属于CPU密集型之外,很多时候都是出现了死循环,或者代码死锁造成的
运行测试代码:
public class TestCPUUseHigh {
public static void main(String[] args) throws Exception {
while (true) {
//这里睡眠一下是为了防止机器受不了
Thread.sleep(10);
System.out.println(1);
}
}
}
//找到进程ID
>jps
22371 TestCPUUseHigh
//显示该进程下的所有线程,找CPU占用高的或者时间占用久的线程ID
>ps -mp 22371 -o THREAD,tid,time | sort -rn
USER %CPU PRI SCNT WCHAN USER SYSTEM TID TIME
XXXXXXXX 0.8 - - - - - - 00:00:00
XXXXXXXX 0.7 19 - futex_ - - 22372 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22384 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22383 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22382 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22381 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22380 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22379 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22378 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22377 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22376 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22375 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22374 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22373 00:00:00
XXXXXXXX 0.0 19 - futex_ - - 22371 00:00:00
//我们看到22372这个ID线程占用cpu比较高,把这个ID转换成16进制
>printf "%x\n" 22372
5764
//jstack打印堆栈,并且过滤这个ID,发现问题
>jstack 22372 |grep 5764 -A 30
"main" prio=10 tid=0x00007f9524008800 nid=0x5764 waiting on condition [0x00007f95293e8000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at TestCPUHighUse.main(TestCPUHighUse.java:7)
内存
JAVA占用内存高,一般都是代码中创建了大量大对象,并且长时间不能被GC
测试代码如下:
public class TestMemoryUseHigh {
public static void main(String[] args) throws Exception {
List<TestObj> list = new ArrayList<TestObj>();
for(int i = 1 ; i < 1000 ; i++){
//放到list里,防止被垃圾回收
list.add(new TestObj());
System.out.println(i);
}
Thread.sleep(1000000);
}
private static class TestObj{
byte[] b = new byte[102400];
}
}
//进程ID
$ jps
27593 TestMemoryUseHigh
//一个jmap命令,内存尽收眼底
//简单说明一下
[C is a char[]
[S is a short[]
[I is a int[]
[B is a byte[]
[[I is a int[][]
$ jmap -histo:live 27593
num #instances #bytes class name
----------------------------------------------
1: 1525 102400792 [B
2: 5577 719008 <methodKlass>
3: 5577 638800 <constMethodKlass>
4: 372 435416 <constantPoolKlass>
5: 336 268512 <constantPoolCacheKlass>
6: 372 254264 <instanceKlassKlass>
7: 875 78336 [C
8: 432 42464 java.lang.Class
9: 605 40560 [[I
10: 566 34808 [S
11: 43 23392 <objArrayKlassKlass>
12: 856 20544 java.lang.String
13: 314 18112 [Ljava.lang.Object;
14: 999 15984 TestMemoryUseHigh$TestObj
15: 79 5688 java.lang.reflect.Field
16: 14 4824 <methodDataKlass>
17: 8 4352 <typeArrayKlassKlass>
18: 90 3600 java.lang.ref.SoftReference
19: 108 3456 java.util.Hashtable$Entry
20: 11 2288 <klassKlass>
21: 53 1928 [Ljava.lang.String;
22: 59 1888 java.util.concurrent.ConcurrentHashMap$HashEntry
23: 46 1840 java.util.concurrent.ConcurrentHashMap$Segment
24: 38 1824 sun.util.locale.LocaleObjectCache$CacheEntry
25: 46 1472 java.util.concurrent.locks.ReentrantLock$NonfairSync
26: 46 1232 [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
27: 3 1112 [I
28: 16 1024 java.net.URL
29: 6 992 [Ljava.util.Hashtable$Entry;
30: 12 960 [Ljava.util.HashMap$Entry;
Total 19653 105048560
顺便提一下jstack命令,上面的cpu的例子中也用到了jstack,这个命令可以打印java虚拟机当前时刻的所有线程快照
因为太长了,我粘贴一段说明一下,例如下面的输出:
"logic worker 8_0" prio=10 tid=0x00007f4c3c3c2800 nid=0x7dd4 waiting for monitor entry [0x00007f4c0fcba000]
java.lang.Thread.State: BLOCKED (on object monitor)
at ......
//这说明这个线程死锁了,为什么呢?
waiting to lock <0x00000005c81872f8> (a java.lang.String)
正在等待这个ID的锁,我们去搜索这个ID
//很明显,这个线程拿着这个锁
- locked <0x00000005c81872f8> (a java.lang.String)