OOM問題分析定位

目錄

一 、問題描述

​二、MAT(Memory Analyzer Tool)分析

1.下載地址

2.獲取dump文件

3.Leak Suspect報告

4.Chart報告

三、代碼問題

四、問題解決


一 、問題描述

      直接上圖,這個是之前在測試環境上發現的問題,導致整個服務崩了。(心裏暗喜,幸虧是測試環境啊,上線那不得...)從打印的日誌可以很清楚的知道啥原因,OOM嘛

     java堆內存溢出原因:內存泄漏或者堆的大小設置不當引起的。對於內存泄露,需要通過內存監控軟件查找程序中的泄露代碼,而堆大小可以通過虛擬機參數-Xms,-Xmx等修改。

    問題分析:

    (1)這個服務在測試環境跑了這麼久,都沒出現這種情況,應該可以排除堆的大小設置不當的原因(正常操作應該是查看堆大小的設置情況進行排查問題,當時抖機靈了hhhh)

    (2)在5分鐘前,我剛剛發了一個版本到測試環境,就出現這問題,感覺大概率是代碼問題

     話不多說,趕緊分析一波代碼。但是,爲了假裝自己是一個比較在行的程序員,還是按流程辦事吧,先搞個dump文件,分析是哪裏出現問題了。


二、MAT(Memory Analyzer Tool)分析

1.下載地址

https://www.eclipse.org/mat/downloads.php

2.獲取dump文件

    登錄服務器,進入到bin目錄下,用java自帶的jmap命令生成dump文件,命令如下:

      ./jmap -dump:format=b,file=/home/xxxxx/heap.hprof pid(進程id)

3.Leak Suspect報告

       從報告中,可以清楚的看到   io/vertx/core/impl/TaskQueue 這個類中的一個屬性 java/util/LinkedList 類型的,佔用了60.83%內存,往上看,這個還是跟kafka消費有點關係。

4.Chart報告

      這個圖也可以清晰的看到,java/util/LinkedList這個類型佔用了較高的內存,那這個肯定是問題的隱患所在嘛。


三、代碼問題

     1.代碼邏輯很簡單,當有消息寫入的時候,則利用vertx框架的異步操作處理邏輯。

vertx.executeBlocking(future->{
    /**
     * 業務代碼邏輯
     */
},null);

   2.查看這個異步操作的執行過程

(1)VertxInternal 接口  Vertx 接口;VertxImpl 類 實現了 VertxInternal 接口,並重寫了 executeBlocking方法

(2)executeBlocking方法分析

     兩個接口的區別之處在於,多了個order參數(是否有序),我的代碼是調用了下面的接口,默認是有序執行。我們在仔細的品一品上面這個方法的實現。ContextImpl 、ContextImpl、ContextImpl 這個類不就是打印的日誌中報oom的類嘛是,說明距離真相已經很近了。

    我們在仔細的看一下這個方法的具體實現,裏面有這麼一段代碼。這個queue就是我們之前報告分析中的TaskQueue。當我們設置了order=true的時候,會創建一個TaskQueue,用於按序存放要執行的任務;同時,由於是按序執行任務,vertx框架只會創建一個工作線程來處理業務邏輯,用於保證有序執行任務。在測試環境只有一臺機器,也就是隻有一個消費者,而我們的生產者大概是一分鐘產生2w條數據,導致TaskQueue中的 tasks 添加了較多的任務而出現OOM。

 private final LinkedList<Task> tasks = new LinkedList<>();
  • ContextImpl 類中的executeBlocking方法
  if (queue != null) {
        queue.execute(command, exec);
      } else {
        exec.execute(command);
      }
  • TaskQueue類中的execute方法
public void execute(Runnable task, Executor executor) {
    synchronized (tasks) {
      tasks.add(new Task(task, executor));
      if (current == null) {
        current = executor;
        executor.execute(runner);
      }
    }
  }

四、問題解決

  1.  將執行異步操作的過程設置會無序的,這樣的話vertx框架會創建一個線程池,用於執行任務
  2.  自己創建一個固定大小的線程池用於執行任務,類似方案(1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章