国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java 使用 VisualVM 排查內(nèi)存泄露

這篇具有很好參考價(jià)值的文章主要介紹了Java 使用 VisualVM 排查內(nèi)存泄露。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1. 問題發(fā)生

線上突發(fā)告警,筆者負(fù)責(zé)的一個(gè)服務(wù)老年代內(nèi)存使用率到達(dá) 75% 閾值,于是立即登錄監(jiān)控系統(tǒng)查看數(shù)據(jù)。拉長時(shí)間周期,查看最近 7 天的 GC 和老年代內(nèi)存占用,監(jiān)控截圖如下。可以看到老年代占用內(nèi)存的最低點(diǎn)在逐步抬升,初步判斷是發(fā)生了內(nèi)存泄露

java visualvm,JVM,隨筆,java,jvm,linux

2. 排查過程

2.1 初步排查

從監(jiān)控上看,這個(gè)服務(wù)的兩個(gè)實(shí)例老年代內(nèi)存占用情況并不一致,其中疑似發(fā)生內(nèi)存泄露的是跑腳本的機(jī)器。于是登錄到目標(biāo)機(jī)器,首先執(zhí)行 jmap -histo 1 | head -n 100 命令查看目標(biāo)進(jìn)程的堆內(nèi)存占用前 100 的對象,發(fā)現(xiàn)其中 SkyWalking 的一個(gè) trace 追蹤對象 NoopSpan 實(shí)例總數(shù)達(dá)到了 2600 萬之巨,內(nèi)存占用也達(dá)到 600M,明顯不正常
java visualvm,JVM,隨筆,java,jvm,linux

2.2 Visual VM 內(nèi)存分析

由于生產(chǎn)環(huán)境控制嚴(yán)格,不允許在線 dump 堆內(nèi)存數(shù)據(jù),于是在預(yù)發(fā)環(huán)境執(zhí)行 jmap -dump:format=b,file=/tmp/dump 1 命令,將有相同問題的 java 進(jìn)程的堆內(nèi)存 dump 下來。下載拿到 dump 文件后,需要打開 VisualVM 加載該文件,以下為操作步驟

  1. 首先打開 VisualVM,點(diǎn)擊截圖中的按鈕加載 dump 文件
    java visualvm,JVM,隨筆,java,jvm,linux

  2. dump 文件加載后,點(diǎn)擊截圖中框出來的按鈕,切換選項(xiàng)卡為查看對象
    java visualvm,JVM,隨筆,java,jvm,linux

  3. 由于筆者初步排查已經(jīng)確定了可疑的實(shí)例為 NoopSpan,故在對象選項(xiàng)卡界面直接過濾該對象,并展示其 相關(guān)引用、GC root。需注意 GC root 是引用鏈的起點(diǎn),從 VisualVM 的分析可以看到 NoopSpan 的實(shí)例都是以 LinkedList 節(jié)點(diǎn)的形式存在,引用鏈條為 FastThreadLocalThread -> threadLocals(ThreadLocalMap) -> table(ThreadLocalMap$Entry[] 數(shù)組) -> [1](ThreadLocalMap$Entry 數(shù)組第一個(gè)元素) -> value(鍵值對 ThreadLocalMap$Entry 的值) -> activeSpanStack (SkyWalking 的 TracingContext 內(nèi)部暫存 span 的 LinkedList) -> 鏈表的一級級前后指針,至此可以猜測是 ThradLocal 使用不當(dāng)(例如 ThreadLocal 使用后沒有remove)導(dǎo)致內(nèi)存泄露
    java visualvm,JVM,隨筆,java,jvm,linux

  4. 確定了引用鏈,則可以看到 NoopSpan 應(yīng)該是被封裝為 LinkedList 的節(jié)點(diǎn)被保存在對象TracingContext#1 的內(nèi)部鏈表 activeSpanStack 中。此時(shí)查看該對象的鏈表的具體元素?cái)?shù)據(jù),可以看到總共有1萬多個(gè)元素,點(diǎn)開第一個(gè)節(jié)點(diǎn),查看該 LocalSpan 的名稱,確定當(dāng)前 SkyWalking 的 trace 記錄的起點(diǎn)為這個(gè) LocalSpan 的創(chuàng)建
    java visualvm,JVM,隨筆,java,jvm,linux

2.3 代碼分析

  1. 在項(xiàng)目中搜索上一節(jié)分析出的 LocalSpan 名稱,發(fā)現(xiàn)創(chuàng)建該 Span 主要是為了在多線程環(huán)境下跨線程傳遞 trace,創(chuàng)建入口為 ContextManager#createLocalSpan() 方法。這個(gè)方法會創(chuàng)建 Trace 上下文對象 TracingContext 并將其設(shè)置到 ThreadLocal 中,創(chuàng)建出 TracingContext 對象后還會調(diào)用其相關(guān)方法創(chuàng)建 LocalSpan 對象,并將創(chuàng)建的 LocalSpan 對象存入 TracingContext 內(nèi)部的 activeSpanStack 鏈表。至此基本印證了 VisualVM 的引用分析,大致確定是 ThreadLocal 的使用導(dǎo)致了內(nèi)存泄露

     public static AbstractSpan createLocalSpan(String operationName) {
         operationName = StringUtil.cut(operationName, OPERATION_NAME_THRESHOLD);
         AbstractTracerContext context = getOrCreate(operationName, false);
         return context.createLocalSpan(operationName);
     }
    
     private static AbstractTracerContext getOrCreate(String operationName, boolean forceSampling) {
         AbstractTracerContext context = CONTEXT.get();
         if (context == null) {
             if (StringUtil.isEmpty(operationName)) {
                 if (logger.isDebugEnable()) {
                     logger.debug("No operation name, ignore this trace.");
                 }
                 context = new IgnoredTracerContext();
             } else {
                 if (EXTEND_SERVICE == null) {
                     EXTEND_SERVICE = ServiceManager.INSTANCE.findService(ContextManagerExtendService.class);
                 }
                 context = EXTEND_SERVICE.createTraceContext(operationName, forceSampling);
             }
             CONTEXT.set(context);
         }
         return context;
     }
    
    
  2. 我們知道,在線程池環(huán)境下使用 ThreadLocal 如果忘記 remove 很容易發(fā)生內(nèi)存泄漏。繼續(xù)閱讀源碼,發(fā)現(xiàn) ThreadLocal 被移除的觸發(fā)點(diǎn)在 ContextManager#stopSpan() 方法,該方法每調(diào)用一次就會將之前添加到 TracingContext 內(nèi)部的 activeSpanStack 鏈表中的 Span 移除,直到鏈表元素?cái)?shù)量為 0 才會去 remove 掉 ThreadLocal

     public static void stopSpan() {
         final AbstractTracerContext context = get();
         if (Objects.isNull(context)) {
             return;
         }
         stopSpan(context.activeSpan(), context);
    
     }
     private static void stopSpan(AbstractSpan span, final AbstractTracerContext context) {
         try {
             if (context.stopSpan(span)) {
                 CONTEXT.remove();
                 RUNTIME_CONTEXT.remove();
             }
         } catch (Throwable t) {
             //
         }
     }
    
  3. 此時(shí)回到項(xiàng)目代碼一看,問題一目了然,代碼中創(chuàng)建了 LocalSpan 但是沒有調(diào)用相關(guān)方法把它 stop 掉,導(dǎo)致 LocalSpan 一直在 TracingContext 內(nèi)部的 activeSpanStack 鏈表中堆積,并且由于鏈表前后指針的存在無法回收,最終導(dǎo)致了內(nèi)存泄漏文章來源地址http://www.zghlxwxcb.cn/news/detail-617027.html

到了這里,關(guān)于Java 使用 VisualVM 排查內(nèi)存泄露的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • VisualVM工具的下載及插件安裝

    VisualVM工具的下載及插件安裝

    VisualVM作為GitHub的獨(dú)立工具分發(fā),并作為GraalVM的可選組件分發(fā)。兩者都是具有相同功能的相同位。獨(dú)立工具在任何兼容的JDK上運(yùn)行,捆綁工具配置為使用主機(jī)GraalVM運(yùn)行。 VisualVM也作為Java VisualVM在Oracle JDK 6~8中分發(fā)。它已在Oracle JDK 9中停產(chǎn)。請參閱升級 Java VisualVM 頁面,了解如

    2024年02月12日
    瀏覽(21)
  • 【JVM故障問題排查心得】「Java技術(shù)體系方向」Java虛擬機(jī)內(nèi)存優(yōu)化之虛擬機(jī)參數(shù)調(diào)優(yōu)原理介紹

    【JVM故障問題排查心得】「Java技術(shù)體系方向」Java虛擬機(jī)內(nèi)存優(yōu)化之虛擬機(jī)參數(shù)調(diào)優(yōu)原理介紹

    本文主要針對于綜合層面上進(jìn)行分析JVM優(yōu)化方案總結(jié)和列舉調(diào)優(yōu)參數(shù)計(jì)劃。主要包含: 調(diào)優(yōu)之逃逸分析(棧上分配) 調(diào)優(yōu)之線程局部緩存(TLAB) 調(diào)優(yōu)之G1回收器 -XX:+DoEscapeAnalysis 逃逸分析(Escape Analysis) 逃逸分析的基本行為就是分析對象動態(tài)作用域:當(dāng)一個(gè)對象在方法中被定

    2024年01月25日
    瀏覽(20)
  • Java線上故障排查(CPU、磁盤、內(nèi)存、網(wǎng)絡(luò)、GC)+JVM性能調(diào)優(yōu)監(jiān)控工具+JVM常用參數(shù)和命令

    Java線上故障排查(CPU、磁盤、內(nèi)存、網(wǎng)絡(luò)、GC)+JVM性能調(diào)優(yōu)監(jiān)控工具+JVM常用參數(shù)和命令

    根據(jù)服務(wù)部署和項(xiàng)目架構(gòu),從如下幾個(gè)方面排查: (1)運(yùn)用服務(wù)器:排查內(nèi)存,cpu,請求數(shù)等; (2)文件圖片服務(wù)器:排查內(nèi)存,cpu,請求數(shù)等; (3)計(jì)時(shí)器服務(wù)器:排查內(nèi)存,cpu,請求數(shù)等; (4)redis服務(wù)器:排查內(nèi)存,cpu,連接數(shù)等; (5)db服務(wù)器:排查內(nèi)存,cpu,連接數(shù)

    2024年02月07日
    瀏覽(29)
  • jvm內(nèi)存溢出排查(使用idea自帶的內(nèi)存泄漏分析工具)

    jvm內(nèi)存溢出排查(使用idea自帶的內(nèi)存泄漏分析工具)

    想分析堆內(nèi)存溢出,一定在運(yùn)行jar包時(shí)就寫上參數(shù) -XX:+HeapDumpOnOutOfMemoryError ,可以看我之前關(guān)于如何運(yùn)行jar包的文章。若你沒有寫??梢詫懮蠀?shù),重啟你的項(xiàng)目,等你的項(xiàng)目發(fā)生下一次堆內(nèi)存溢出異常,在運(yùn)行的同級文件夾,將產(chǎn)生類似這樣一個(gè)文件 java_pid74935.hprof ,若你

    2024年02月09日
    瀏覽(30)
  • C++內(nèi)存泄露排查的一個(gè)案例

    C++內(nèi)存泄露排查的一個(gè)案例

    背景: 這熟悉的線條. 請求量沒啥波動, 不用懷疑, 就是內(nèi)存泄露了. 方案一 Valgrind Valgrind可以用來檢測是否有非法使用內(nèi)存的問題, 如: 訪問未初始化的內(nèi)存,訪問數(shù)組越界, 忘記釋放動態(tài)內(nèi)存的問題; 首先需要定位是哪個(gè)進(jìn)程的內(nèi)存泄露. 使用top命令, 然后shift+m按照內(nèi)存排序, 找

    2024年02月13日
    瀏覽(29)
  • Java 內(nèi)存泄露問題詳解

    目錄 1、什么是內(nèi)存泄露? 2、Java 中可能導(dǎo)致內(nèi)存泄露的場景 3、長生命周期對象持有短生命周期對象引用造成的內(nèi)存泄露問題示例 4、靜態(tài)集合類持有對象引用造成內(nèi)存泄露問題的示例 1、什么是內(nèi)存泄露? ????????內(nèi)存泄露指的是程序運(yùn)行時(shí)未能正確釋放不再使用的內(nèi)

    2024年02月09日
    瀏覽(24)
  • Linux C/C++ 程序內(nèi)存泄露排查

    由于C/C++程序可以動態(tài)申請內(nèi)存,動態(tài)申請的內(nèi)存位于程序的隊(duì)區(qū),如果程序比較復(fù)雜,程序員在編寫代碼的時(shí)候不小心,可能會存在申請了內(nèi)存沒有釋放的情況,程序長期運(yùn)行,會導(dǎo)致系統(tǒng)中用戶程序可分配堆內(nèi)存越來越少的,最終程序OOM崩潰。 /proc/meminfo 文件保存了系統(tǒng)

    2024年02月03日
    瀏覽(24)
  • C++經(jīng)典面試題:內(nèi)存泄露是什么?如何排查?

    1.內(nèi)存泄露的定義:內(nèi)存泄漏簡單的說就是申請了?塊內(nèi)存空間,使?完畢后沒有釋放掉。 它的?般表現(xiàn)?式是程序運(yùn)?時(shí)間越?,占?內(nèi)存越多,最終?盡全部內(nèi)存,整個(gè)系統(tǒng)崩潰。由程序申請的?塊內(nèi)存,且沒有任何?個(gè)指針指向它,那么這塊內(nèi)存就泄漏了。 2.如何檢測

    2024年02月07日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包