對於java虛擬機,像我這樣工作才兩年的會是比較陌生和神秘,但是時候,需要對JVM有一定的認識,並且能夠設置一些參數。下面是自己學習到的內容。
這里需要使用一個java自帶的一個工具,VisualVM。使用IDEA下載一個VisualVM。
一、查看程序的JVM內存
首先任務參數有不要設置,然后編寫一個程序。
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,該異常就是設置的堆內存太小導致,但是一般情況下不會出現該情況,因為上面的程序並不需要特別大的程序,可能是我的筆記本電腦的原因。
上面知道看堆的大小,接下來可以看一下堆中存儲了什么。在程序運行的時候,需要快速點擊堆dump,然后就看到如下
雙擊某個列表之后查看其中的內容,而存儲最多的就是程序中設置的tempOOM參數,此時知道了堆中存儲最大的內容是什么,如果是其他程序,某一個字段占用特多的內存,可能就是程序出現問題了,那么就需要對那個字段進行優化。
二、查看程序的線程情況
接下來運行下面的程序:
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++; } } }
程序運行之后,查看線程標簽后直接告警出現了死鎖的線程。
上面的程序可以看到藍色部分為線程正常運行,黃色為等待。
三、使用VisualGC來查看年輕代,老年代的堆內存的GC情況,如果是頻繁的GC,那么可能就是內存不足,就需要增加堆內存。
上面的圖大部分的GC都是在Eden區,即對象都是朝生暮死的,並且發生了GC time收集到0條GC,那么就是該程序一直運行可以(這里程序運行時間很短,在長時間觀察,可以得到更多的信息,如果是將堆內存設置很小的時候,那么就會經常發生GC的情況)
JVM調優,需要變設置參數,邊進行觀察,這樣更容易理解其中緣由,可以上手試一試。