一 举个死锁的例子
public class DeadLock {
public static void main(String[] args) {
new Thread(A::getA,"ThreadA").start();
new Thread(B::getB,"ThreadB").start();
}
}
class A {
public static synchronized void getA(){
System.out.println("进入A");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
B.getB();
}
}
class B {
public static synchronized void getB(){
System.out.println("进入B");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
A.getA();
}
}
类的静态方法是属于类的对象,与类的实例没有关系。
1.jvisualvm


2.jstack
jstack pid,结果如下
Found one Java-level deadlock:
=============================
"ThreadB":
waiting to lock monitor 0x00007fa54b8086a8 (object 0x000000076bb588f0, a java.lang.Class),
which is held by "ThreadA"
"ThreadA":
waiting to lock monitor 0x00007fa54b808808 (object 0x000000076bdcaf78, a java.lang.Class),
which is held by "ThreadB"
Java stack information for the threads listed above:
===================================================
"ThreadB":
at jvm.newjvm.A.getA(DeadLock.java:13)
- waiting to lock <0x000000076bb588f0> (a java.lang.Class for jvm.newjvm.A)
at jvm.newjvm.B.getB(DeadLock.java:31)
- locked <0x000000076bdcaf78> (a java.lang.Class for jvm.newjvm.B)
at jvm.newjvm.DeadLock$$Lambda$2/1535128843.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
"ThreadA":
at jvm.newjvm.B.getB(DeadLock.java:25)
- waiting to lock <0x000000076bdcaf78> (a java.lang.Class for jvm.newjvm.B)
at jvm.newjvm.A.getA(DeadLock.java:19)
- locked <0x000000076bb588f0> (a java.lang.Class for jvm.newjvm.A)
at jvm.newjvm.DeadLock$$Lambda$1/1463801669.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
3.jcmd
jcmd 64507 Thread.print
Found one Java-level deadlock:
=============================
"ThreadB":
waiting to lock monitor 0x00007fa54b8086a8 (object 0x000000076bb588f0, a java.lang.Class),
which is held by "ThreadA"
"ThreadA":
waiting to lock monitor 0x00007fa54b808808 (object 0x000000076bdcaf78, a java.lang.Class),
which is held by "ThreadB"
Java stack information for the threads listed above:
===================================================
"ThreadB":
at jvm.newjvm.A.getA(DeadLock.java:13)
- waiting to lock <0x000000076bb588f0> (a java.lang.Class for jvm.newjvm.A)
at jvm.newjvm.B.getB(DeadLock.java:31)
- locked <0x000000076bdcaf78> (a java.lang.Class for jvm.newjvm.B)
at jvm.newjvm.DeadLock$$Lambda$2/1535128843.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
"ThreadA":
at jvm.newjvm.B.getB(DeadLock.java:25)
- waiting to lock <0x000000076bdcaf78> (a java.lang.Class for jvm.newjvm.B)
at jvm.newjvm.A.getA(DeadLock.java:19)
- locked <0x000000076bb588f0> (a java.lang.Class for jvm.newjvm.A)
at jvm.newjvm.DeadLock$$Lambda$1/1463801669.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
用以上三个工具都可以看出线程死锁的信息。
二 GC垃圾收集过程
代码如下:
int size = 1024 * 1024;
Byte[] byte1 = new Byte[2*size];
Byte[] byte2 = new Byte[2*size];
Byte[] byte3 = new Byte[2*size];
Byte[] byte4 = new Byte[2*size];
System.out.println("hello world!");
设置VM Options 如下:
-verbose:gc 输出冗余的gc信息
-Xms20M 堆初始化最小的容量
-Xmx20M 堆初始化最大的容量
-Xmn10M 新生代容量
-XX:+PrintGCDetails
-XX:SurvivorRatio=8 配置新生代和survivor的大小比例为8:1:1
run下程序的结果如下:
[GC (Allocation Failure) [PSYoungGen: 2238K->867K(9216K)] 10430K->9067K(19456K), 0.0010796 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 867K->851K(9216K)] 9067K->9051K(19456K), 0.0008617 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 851K->0K(9216K)] [ParOldGen: 8200K->8889K(10240K)] 9051K->8889K(19456K), [Metaspace: 3118K->3118K(1056768K)], 0.0133250 secs] [Times: user=0.07 sys=0.00, real=0.02 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(9216K)] 8889K->8889K(19456K), 0.0004353 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(9216K)] [ParOldGen: 8889K->8873K(10240K)] 8889K->8873K(19456K), [Metaspace: 3118K->3118K(1056768K)], 0.0127611 secs] [Times: user=0.08 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 9216K, used 410K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
eden space 8192K, 5% used [0x00000007bf600000,0x00000007bf666800,0x00000007bfe00000)
from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
to space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
ParOldGen total 10240K, used 8873K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
object space 10240K, 86% used [0x00000007bec00000,0x00000007bf4aa558,0x00000007bf600000)
Metaspace used 3194K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 348K, capacity 388K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at jvm.newjvm.GCTest1.main(GCTest1.java:16)
先看第一行信息,做第一次Minor垃圾回收。
[GC (Allocation Failure) [PSYoungGen: 2238K->867K(9216K)] 10430K->9067K(19456K), 0.0010796 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
9216K PSYoungGen 年轻代有9M的可用空间,从2238k回收到867k 已回收空间为1371k。
10430K->9067K(19456K) 19456k为19M的空间可用,堆由于设置了新生代和survivor的大小比例为8:1:1那么新生代有1M的空间是无法使用的。所用总共的空间为19M。
[GC (Allocation Failure) [PSYoungGen: 867K->851K(9216K)] 9067K->9051K(19456K), 0.0008617 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
第二次垃圾回收。相比第一次并没有回收掉多少空间。可以看到9051k-851k =8200k基本等于8M的空间,基本都在老年代。
[Full GC (Allocation Failure) [PSYoungGen: 851K->0K(9216K)] [ParOldGen: 8200K->8889K(10240K)] 9051K->8889K(19456K), [Metaspace: 3118K->3118K(1056768K)], 0.0133250 secs] [Times: user=0.07 sys=0.00, real=0.02 secs]
第三次发生一次Full GC。操作完的结果是新生代从851k直接到0,老年代8200到8889,没有回收多大的空间。
[GC (Allocation Failure) [PSYoungGen: 0K->0K(9216K)] 8889K->8889K(19456K), 0.0004353 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(9216K)] [ParOldGen: 8889K->8873K(10240K)] 8889K->8873K(19456K), [Metaspace: 3118K->3118K(1056768K)], 0.0127611 secs] [Times: user=0.08 sys=0.00, real=0.01 secs]
接下来有发生一次Minor GC,完全没什么变化。 再发生一次Full GC,变化也不太大。