实战 内存溢出定位与分析
/**
* 模拟测试插入一百万条字符串[image.png](https://img.hacpai.com/file/2019/08/image-dd10de62.png) str += UUID.randomUUID().toString();
}
list.add(str);
}
System.out.println("ok");
}
}
结果:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid10272.hprof ...
Heap dump file created [8323049 bytes in 0.028 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at cn.jeff.test.Test01.main(Test01.java:18)
Process finished with exit code 1
参数中设置了输出dump文件,默认输出在项目根目录下。
可以看出87.93%的内存被Object[]数组占用了,通常情况下不会出现这么高的占用 再去看详细的数据情况:
可以看出在Object[]数组中装满了刚才生产的UUID,导致了最后的系统内存溢出问题。
线程的六种状态
public class TestDeadLock {
// 定义两个锁
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public static void main(String[] args) {
// 创建初始态线程
Thread thread1 = new Thread(new Thread1());
Thread thread2 = new Thread(new Thread2());
// 就绪态
thread1.start();
thread2.start();
}
// 第一个线程
private static class Thread1 implements Runnable {
@Override
public void run() {
synchronized (obj1) {
// 此时得到了obj1这个锁
System.out.println("Thread1得到了obj1这把锁!");
try {
// 停下来休息两秒 为了让Thread2得到obj2这把锁 造成死锁 sleep方法是不会释放锁的
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2) {
System.out.println("Thread1得到了obj2这把锁!");
}
}
}
}
// 第二个线程
private static class Thread2 implements Runnable {
@Override
public void run() {
// 得到obj2这把锁
synchronized (obj2) {
System.out.println("Thread2得到了obj2这把锁!");
try {
// 为了让obj1被先得到
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 得到obj1
synchronized (obj1) {
System.out.println("Thread2得到了obj1这把锁!");
}
}
}
}
}
[root@hadoop101 jvm]# javac TestDeadLock.java
[root@hadoop101 jvm]# java TestDeadLock
Thread1得到了obj1这把锁!
Thread2得到了obj2这把锁!
# 程序卡在这里
保持程序的运行状态,另外创建一个xshell命令行窗口
# 通过jps找到运行的TestDeadLock程序的端口
[root@hadoop101 ~]# jps
2956 TestDeadLock
3038 Jps
1967 Bootstrap
# 指令格式:jstack 端口号
[root@hadoop101 ~]# jstack 2956
2019-08-16 02:43:12
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.111-b14 mixed mode):
"Attach Listener" #11 daemon prio=9 os_prio=0 tid=0x00007ffa54001000 nid=0xbf4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"DestroyJavaVM" #10 prio=5 os_prio=0 tid=0x00007ffa7c008800 nid=0xb8d waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #9 prio=5 os_prio=0 tid=0x00007ffa7c0ca800 nid=0xb97 waiting for monitor entry [0x00007ffa6c51d000]
java.lang.Thread.State: BLOCKED (on object monitor)
at TestDeadLock$Thread2.run(TestDeadLock.java:52)
- waiting to lock <0x00000000e345be78> (a java.lang.Object)
- locked <0x00000000e345be88> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Thread-0" #8 prio=5 os_prio=0 tid=0x00007ffa7c0c9000 nid=0xb96 waiting for monitor entry [0x00007ffa6c61e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at TestDeadLock$Thread1.run(TestDeadLock.java:31)
- waiting to lock <0x00000000e345be88> (a java.lang.Object)
- locked <0x00000000e345be78> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007ffa7c0b3000 nid=0xb94 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007ffa7c0b0000 nid=0xb93 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007ffa7c0ad800 nid=0xb92 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007ffa7c0ac000 nid=0xb91 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007ffa7c079000 nid=0xb90 in Object.wait() [0x00007ffa6cc24000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000e3408e98> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x00000000e3408e98> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007ffa7c074800 nid=0xb8f in Object.wait() [0x00007ffa6cd25000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000e3406b40> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000e3406b40> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=0 tid=0x00007ffa7c06d000 nid=0xb8e runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007ffa7c0b6000 nid=0xb95 waiting on condition
JNI global references: 6
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00007ffa600062c8 (object 0x00000000e345be78, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00007ffa60004e28 (object 0x00000000e345be88, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at TestDeadLock$Thread2.run(TestDeadLock.java:52)
- waiting to lock <0x00000000e345be78> (a java.lang.Object)
- locked <0x00000000e345be88> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Thread-0":
at TestDeadLock$Thread1.run(TestDeadLock.java:31)
- waiting to lock <0x00000000e345be88> (a java.lang.Object)
- locked <0x00000000e345be78> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
# 系统提示发现一个死锁
Found 1 deadlock.
"Thread-1" #9 prio=5 os_prio=0 tid=0x00007ffa7c0ca800 nid=0xb97 waiting for monitor entry [0x00007ffa6c51d000]
java.lang.Thread.State: BLOCKED (on object monitor)
at TestDeadLock$Thread2.run(TestDeadLock.java:52)
- waiting to lock <0x00000000e345be78> (a java.lang.Object)
- locked <0x00000000e345be88> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Thread-0" #8 prio=5 os_prio=0 tid=0x00007ffa7c0c9000 nid=0xb96 waiting for monitor entry [0x00007ffa6c61e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at TestDeadLock$Thread1.run(TestDeadLock.java:31)
- waiting to lock <0x00000000e345be88> (a java.lang.Object)
- locked <0x00000000e345be78> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
可以看出: Thread-1:正在手握着0x00000000e345be88这个锁,等待着0x00000000e345be78的获取; Thread-0:正在手握着0x00000000e345be78这个锁,等待着0x00000000e345be88的获取;
VisualVM,能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)。 VisualVM使用简单,几乎0配置,功能还是比较丰富的,几乎囊括了其它JDK自带命令的所有功能。 1、内存信息 2、线程信息 3、Dump堆(本地进程) 4、Dump线程(本地进程) 5、打开堆Dump。堆Dump可以用jmap来生成。 6、打开线程Dump 7、生成应用快照(包含内存信息、线程信息等等) 8、性能分析。 9、CPU分析(各个方法调用时间,检查哪些方法耗时多) 10、内存分析(各类对象占用的内存,检查哪些类占用内存多
VisualVM在jdk的安装目录的bin下面有jvisualvm.exe,打开便可使用。