1. 程式人生 > >jmap MAT記憶體溢位實踐

jmap MAT記憶體溢位實踐

jmap MAT記憶體溢位實踐

 

一、建立Spring Boot工程

進入https://start.spring.io/網站,配置如下圖

點選建立工程,然後用Idea或者Eclipse開啟

 

二、建立模擬Heap記憶體溢位的程式碼

1、建立MemoryController類

 

2、建立User類

public class User {
    private int id;
    private String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

  

3、 設定最大記憶體和最小記憶體為32M

-Xmx32M -Xms32M

 

4、執行工程

http://127.0.0.1:8080/heap

出現記憶體溢位

 

三、建立模擬非Heap記憶體溢位

1、引入asm

		<dependency>
			<groupId>asm</groupId>
			<artifactId>asm</artifactId>
			<version>3.3.1</version>
		</dependency>

  

2、建立Metaspace類

/**
 * https://blog.csdn.net/bolg_hero/article/details/78189621
 * 繼承ClassLoader是為了方便呼叫defineClass方法,因為該方法的定義為protected
 */
public class Metaspace  extends ClassLoader{

    public static List<Class<?>> createClasses() {
        // 類持有
        List<Class<?>> classes = new ArrayList<Class<?>>();
        // 迴圈1000w次生成1000w個不同的類。
        for (int i = 0; i < 10000000; ++i) {
            ClassWriter cw = new ClassWriter(0);
            // 定義一個類名稱為Class{i},它的訪問域為public,父類為java.lang.Object,不實現任何介面
            cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Class" + i, null,
                    "java/lang/Object", null);
            // 定義建構函式<init>方法
            MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
                    "()V", null, null);
            // 第一個指令為載入this
            mw.visitVarInsn(Opcodes.ALOAD, 0);
            // 第二個指令為呼叫父類Object的建構函式
            mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object",
                    "<init>", "()V", false);
            // 第三條指令為return
            mw.visitInsn(Opcodes.RETURN);
            mw.visitMaxs(1, 1);
            mw.visitEnd();

            Metaspace test = new Metaspace();
            byte[] code = cw.toByteArray();
            // 定義類
            Class<?> exampleClass = test.defineClass("Class" + i, code, 0, code.length);
            classes.add(exampleClass);
        }
        return  classes;
    }

}

  

3、建立呼叫方式

    private List<Class<?>>  classList = new ArrayList<>();

  

    /**
     * -XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M
     *
     * @return
     */
    @GetMapping("/nonheap")
    public String nonheap(){
        while (true){
            classList.addAll(Metaspace.createClasses());
        }
    }

  

 4、設定JVM引數

-XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M

 

5、啟動呼叫

http://127.0.0.1:8080/nonheap

 發現記憶體溢位

Exception in thread "http-nio-8080-exec-4" java.lang.OutOfMemoryError: Metaspace

 

 

四、解決方法

如果生成環境出現記憶體溢位,應該如何解決呢

 1、匯出記憶體映像檔案

1)記憶體溢位自動匯出

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=./

配置如下

-Xmx32M -Xms32M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./

然後呼叫http://localhost:8080/heap

顯示hprof檔案已經生成了

 

 

2)使用jmap命令手動匯出

   jmap -dump:format=b,file=heap.hprof 15296

 

  15296是tomcat的程序。 這樣就生成了一個heap.hprof 檔案

 

jmap -heap 5579 檢視記憶體的使用,每個區塊佔有多少記憶體(5579是tomcat的程序)

 

2、MAT分析記憶體映像檔案

現在MAT工具 http://www.eclipse.org/mat/downloads.php

我這裡下載的是Windows (x86_64)版本

然後使用這個工具開啟剛才生成的hprof檔案