1.美图
2.概述
3.安装
File-> Setting-> Plugins -> Browers Repositrories
搜索VisualVM Launcher安装并重启IDEA。
出现下图中的两个按钮即为安装成功,当我们通过他们启动项目时,会自动打开VisualVM控制台面板。
4.查看程序的JVM内存
首先任务参数有不要设置,然后编写一个程序。
package com.java.book.jvm.chapter4;
public class JavaHeapTest {
public final static int OUTOFMEMORY = 200000000;
private String oom;
private int length;
StringBuffer tempOOM = new StringBuffer();
public JavaHeapTest(int leng) {
this.length = leng;
int i = 0;
while (i < leng) {
i++;
try {
tempOOM.append("a");
} catch (OutOfMemoryError e) {
e.printStackTrace();
break;
}
}
this.oom = tempOOM.toString();
}
public String getOom() {
return oom;
}
public int getLength() {
return length;
}
public static void main(String[] args) {
JavaHeapTest javaHeapTest = new JavaHeapTest(OUTOFMEMORY);
System.out.println(javaHeapTest.getOom().length());
}
}
然后使用VIsualVM运行程序。
程序运行起来,但是第一次需要设置VisualVM的位置
程序运行起来后后堆的情况。(下面这个标签页会自动跳出来)
上面的图是没有设置任何程序的事情下做的,为什么需要看堆的大小,因为堆存放对象的实例,一般都会需要设置该值,在没有做任何设置的时候,就会看到堆的内存可能达到1G的大小。有时候需要模拟线上环境的上的Java内存大小,在IDEA中设置下一年堆的大小,这里设置堆的初始化和最大值都一样,以避免每次垃圾回收完成后JVM重新分配内存
设置之后运行程序,堆的内存变为设置的大小,但是这个时候有可能出现异常,在我的电脑上就出现 java.lang.OutOfMemoryError: Java heap space
,异常栈如下
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.StringBuffer.append(StringBuffer.java:270)
at com.java.book.jvm.chapter4.JavaHeapTest.<init>(JavaHeapTest.java:19)
at com.java.book.jvm.chapter4.JavaHeapTest.main(JavaHeapTest.java:38)
75497470
该异常就是设置的堆内存太小导致,但是一般情况下不会出现该情况,因为上面的程序并不需要特别大的程序,可能是我的笔记本电脑的原因。
这里有个疑问?设置的额是512M,为何还没达到512M就OOM了呢?
上面知道看堆的大小,接下来可以看一下堆中存储了什么。在程序运行的时候,需要快速点击堆dump,然后就看到如下
双击某个列表之后查看其中的内容,而存储最多的就是程序中设置的tempOOM
参数,此时知道了堆中存储最大的内容是什么,如果是其他程序,某一个字段占用特多的内存,可能就是程序出现问题了,那么就需要对那个字段进行优化。
5.查看程序的线程情况
package com.java.book.jvm.chapter4;
public class DeadLock {
public static void main(String[] args) {
Resource r1 = new Resource();
Resource r0 = new Resource();
Thread myTh1 = new LockThread1(r1, r0);
Thread myTh0 = new LockThread0(r1, r0);
myTh1.setName("DeadLock-1 ");
myTh0.setName("DeadLock-0 ");
myTh1.start();
myTh0.start();
}
}
class Resource {
private int i;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
class LockThread1 extends Thread {
private Resource r1, r2;
public LockThread1(Resource r1, Resource r2) {
this.r1 = r1;
this.r2 = r2;
}
@Override
public void run() {
int j = 0;
while (true) {
synchronized (r1) {
System.out.println("The first thread got r1's lock " + j);
synchronized (r2) {
System.out.println("The first thread got r2's lock " + j);
}
}
j++;
}
}
}
class LockThread0 extends Thread {
private Resource r1, r2;
public LockThread0(Resource r1, Resource r2) {
this.r1 = r1;
this.r2 = r2;
}
@Override
public void run() {
int j = 0;
while (true) {
synchronized (r2) {
System.out.println("The second thread got r2's lock " + j);
synchronized (r1) {
System.out.println("The second thread got r1's lock" + j);
}
}
j++;
}
}
}
程序运行之后,查看线程标签后直接告警出现了死锁的线程。
上面的程序可以看到蓝色部分为线程正常运行,黄色为等待。
dump信息如下
"DestroyJavaVM" #12 prio=5 os_prio=31 tid=0x00007f9285803000 nid=0x2603 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"DeadLock-0 " #11 prio=5 os_prio=31 tid=0x00007f9284825000 nid=0x4103 waiting for monitor entry [0x000070001094b000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.java.book.jvm.chapter4.LockThread0.run(DeadLock.java:71)
- waiting to lock <0x00000007956b75d8> (a com.java.book.jvm.chapter4.Resource)
- locked <0x00000007956b75e8> (a com.java.book.jvm.chapter4.Resource)
Locked ownable synchronizers:
- None
"DeadLock-1 " #10 prio=5 os_prio=31 tid=0x00007f92850ea800 nid=0x4303 waiting for monitor entry [0x0000700010848000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.java.book.jvm.chapter4.LockThread1.run(DeadLock.java:47)
- waiting to lock <0x00000007956b75e8> (a com.java.book.jvm.chapter4.Resource)
- locked <0x00000007956b75d8> (a com.java.book.jvm.chapter4.Resource)
6.VisualGC
使用VisualGC来查看年轻代,老年代的堆内存的GC情况,如果是频繁的GC,那么可能就是内存不足,就需要增加堆内存。
界面介绍
案例
上面的图大部分的GC都是在Eden区,即对象都是朝生暮死的,并且发生了GC time收集到0条GC,那么就是该程序一直运行可以(这里程序运行时间很短,在长时间观察,可以得到更多的信息,如果是将堆内存设置很小的时候,那么就会经常发生GC的情况)