《Java 底層原理》Jvm性能調優

前言

Java 的性能調優,主要就是爲了防止出現out of memory(oom)。Java出現oom就會直接導致程序停止運行。

調優

模擬元空間oom的情況

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MetaSpaceOverTest {

    public static void main(String[] args) throws InterruptedException {
        while (true){
            Thread.sleep(20);

            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MetaSpaceOverTest.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invoke(o,objects);
                }
            });
            enhancer.create();
        }
    }
}

需要設置的參數:-XX:+PrintGCDetails -XX:MetaspaceSize=20M -XX:MaxMetaspaceSize=20M      分別是打印GC日誌,設置元空間的內存初始值的最大值。

代碼中使用了CGLib的jar包:具體說明見:https://www.cnblogs.com/jssj/p/12635206.html

運行結果:

Metaspace 空間出現oom的情況,通過jvisualvm 工具可以比較清楚的看到元空間的使用情況。

GC日誌說明:

[GC (Metadata GC Threshold) [PSYoungGen: 555K->128K(35328K)] 4349K->3922K(105472K), 0.0012436 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Metadata GC Threshold) [PSYoungGen: 128K->0K(35328K)] [ParOldGen: 3794K->3789K(108544K)] 3922K->3789K(143872K), [Metaspace: 19831K->19831K(1067008K)], 0.0169102 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 

GC (Metadata GC Threshold): 這是一個young GC,表示GC作用的內存位置,Metadata是元空間的意思。

[PSYoungGen: 555K->128K(35328K)] :這是一個youngGC 新生代堆區從555K 變成 128K, 新生代堆區總大小是35328K。

4349K->3922K(105472K) :總堆區從4349K到3922K, 總堆區的大小105472K。

0.0012436 secs:GC消耗的時間。 

 

Full GC (Metadata GC Threshold) : 這是一個Full GC。

[PSYoungGen: 128K->0K(35328K)]:新生代對象佔用內存移動到了老年代。

[ParOldGen: 3794K->3789K(108544K)]:老年代堆區從3794K->3789K。

3922K->3789K(143872K):整個堆區的變化情況。

[Metaspace: 19831K->19831K(1067008K)]:元空間的佔用內存的變化情況。這裏可以看到已經快超20M。

重點:方法區調優,-XX:MetaspaceSize=20M -XX:MaxMetaspaceSize=20M 兩個參數設置一樣大,程序運行後查詢元空間被使用的情況,在這個基礎上加20%的。查看元空間的使用情況可以使用工具:jvisualvm

模擬堆區的oom

import java.util.ArrayList;
import java.util.List;

public class HeapOverTest {

    int[] intArr = new int[50];

    public static void main(String[] args) throws InterruptedException {
        List<HeapOverTest> heapOverTestList = new ArrayList<>();
        for(;;){
            Thread.sleep(1);
            heapOverTestList.add(new HeapOverTest());
        }
    }
}
-Xmx10m -Xms10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:

Jvm 參數設置堆的最大最小內存大小和打印GC日誌, 剩下的是用於打印日誌和將Heap信息的日誌存放到D盤。

運行結果:(運行一段時間會出現這個報錯。)

利用該工具可以很好的看出來堆內存的使用情況。

根據前面的信息,我們已經獲取到一個HeapOOM的日誌,我們來分析看看。

上傳日誌分析,點擊類視圖,查看什麼對象比較佔用內存。

 

可以比較明顯的看出什麼比較暫用內存。當然生產環境會比這個大很多很多,分析也會更加複雜。

這裏的int[] 我們其實還不知道具體是被哪個對象引用,所以我需要查看被引用對象。

然後找到他的引用對象:

堆區調優:堆區最大值和最小值調整一樣大,防止內存抖動,具體調整多大根據程序正常運行下再加30%。

-Xmx10m   設置堆內存的最大值
-Xms10m   設置堆內存的最小值

虛擬機棧-OOM

public class StackOverTest {

    private int val = 0;

    public void test(){
        val++;
        test();
    }

    public static void main(String[] args) {
        StackOverTest stackOverTest = new StackOverTest();
        try {
            stackOverTest.test();
        } catch (Throwable e) {
            System.out.println("棧深度:"+stackOverTest.val);
        }
    }
}

運行結果:

這個棧深度每次運行會出現略微的差別:原因是因爲會出現棧上分配,輕量級鎖的存在。

-Xss100K      設置虛擬機棧大小,部分機器最小要求不同

Java Agent

待補充

實戰

1. 死鎖

2. CPU消耗高

top -H -p 6290      --6290是進程號

總結

Jvm性能調優是Java工程師的必修課。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章