精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

一次完整的JVM堆外內存泄漏故障排查記錄

云計算 虛擬化
記錄一次線上JVM堆外內存泄漏問題的排查過程與思路,其中夾帶一些「JVM內存分配的原理分析」以及「常用的JVM問題排查手段和工具分享」,希望對大家有所幫助。

 [[339593]]

前言

記錄一次線上JVM堆外內存泄漏問題的排查過程與思路,其中夾帶一些「JVM內存分配的原理分析」以及「常用的JVM問題排查手段和工具分享」,希望對大家有所幫助。

在整個排查過程中,我也走了不少彎路,但是在文章中我仍然會把完整的思路和想法寫出來,當做一次經驗教訓,給后人參考,文章最后也總結了下內存泄漏問題快速排查的幾個原則。

「本文的主要內容:」

  • 故障描述和排查過程
  • 故障原因和解決方案分析
  • JVM堆內內存和堆外內存分配原理
  • 常用的進程內存泄漏排查指令和工具介紹和使用

故障描述

8月12日中午午休時間,我們商業服務收到告警,服務進程占用容器的物理內存(16G)超過了80%的閾值,并且還在不斷上升。

 

監控系統調出圖表查看:

 

像是Java進程發生了內存泄漏,而我們堆內存的限制是4G,這種大于4G快要吃滿內存應該是JVM堆外內存泄漏。

確認了下當時服務進程的啟動配置:

  1. -Xms4g -Xmx4g -Xmn2g -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80 

雖然當天沒有上線新代碼,但是「當天上午我們正在使用消息隊列推送歷史數據的修復腳本,該任務會大量調用我們服務其中的某一個接口」,所以初步懷疑和該接口有關。

下圖是該調用接口當天的訪問量變化:

 

可以看到案發當時調用量相比正常情況(每分鐘200+次)提高了很多(每分鐘5000+次)。

「我們暫時讓腳本停止發送消息,該接口調用量下降到每分鐘200+次,容器內存不再以極高斜率上升,一切似乎恢復了正常。」

接下來排查這個接口是不是發生了內存泄漏。

排查過程

首先我們先回顧下Java進程的內存分配,方便我們下面排查思路的闡述。

「以我們線上使用的JDK1.8版本為例」。JVM內存分配網上有許多總結,我就不再進行二次創作。

JVM內存區域的劃分為兩塊:堆區和非堆區。

  • 堆區:就是我們熟知的新生代老年代。
  • 非堆區:非堆區如圖中所示,有元數據區和直接內存。

 

「這里需要額外注意的是:永久代(JDK8的原生去)存放JVM運行時使用的類,永久代的對象在full GC時進行垃圾收集。」

復習完了JVM的內存分配,讓我們回到故障上來。

堆內存分析

雖說一開始就基本確認與堆內存無關,因為泄露的內存占用超過了堆內存限制4G,但是我們為了保險起見先看下堆內存有什么線索。

我們觀察了新生代和老年代內存占用曲線以及回收次數統計,和往常一樣沒有大問題,我們接著在事故現場的容器上dump了一份JVM堆內存的日志。

堆內存Dump

堆內存快照dump命令:

  1. jmap -dump:live,format=b,file=xxxx.hprof pid 

畫外音:你也可以使用jmap -histo:live pid直接查看堆內存存活的對象。

導出后,將Dump文件下載回本地,然后可以使用Eclipse的MAT(Memory Analyzer)或者JDK自帶的JVisualVM打開日志文件。

使用MAT打開文件如圖所示:

 

「可以看到堆內存中,有一些nio有關的大對象,比如正在接收消息隊列消息的nioChannel,還有nio.HeapByteBuffer,但是數量不多,不能作為判斷的依據,先放著觀察下。」

下一步,我開始瀏覽該接口代碼,接口內部主要邏輯是調用集團的WCS客戶端,將數據庫表中數據查表后寫入WCS,沒有其他額外邏輯

發覺沒有什么特殊邏輯后,我開始懷疑WCS客戶端封裝是否存在內存泄漏,這樣懷疑的理由是,WCS客戶端底層是由SCF客戶端封裝的,作為RPC框架,其底層通訊傳輸協議有可能會申請直接內存。

「是不是我的代碼出發了WCS客戶端的Bug,導致不斷地申請直接內存的調用,最終吃滿內存。」

我聯系上了WCS的值班人,將我們遇到的問題和他們描述了一下,他們回復我們,會在他們本地執行下寫入操作的壓測,看看能不能復現我們的問題。

既然等待他們的反饋還需要時間,我們就準備先自己琢磨下原因。

「我將懷疑的目光停留在了直接內存上,懷疑是由于接口調用量過大,客戶端對nio使用不當,導致使用ByteBuffer申請過多的直接內存。」

「畫外音:最終的結果證明,這一個先入為主的思路導致排查過程走了彎路。在問題的排查過程中,用合理的猜測來縮小排查范圍是可以的,但最好先把每種可能性都列清楚,在發現自己深入某個可能性無果時,要及時回頭仔細審視其他可能性。」

沙箱環境復現

為了能還原當時的故障場景,我在沙箱環境申請了一臺壓測機器,來確保和線上環境一致。

「首先我們先模擬內存溢出的情況(大量調用接口):」

我們讓腳本繼續推送數據,調用我們的接口,我們持續觀察內存占用。

當開始調用后,內存便開始持續增長,并且看起來沒有被限制住(沒有因為限制觸發Full GC)。

 

「接著我們來模擬下平時正常調用量的情況(正常量調用接口):」

我們將該接口平時正常的調用量(比較小,且每10分鐘進行一次批量調用)切到該壓測機器上,得到了下圖這樣的老生代內存和物理內存趨勢:

 

「問題來了:為何內存會不斷往上走吃滿內存呢?」

當時猜測是由于JVM進程并沒有對于直接內存大小進行限制(-XX:MaxDirectMemorySize),所以堆外內存不斷上漲,并不會觸發FullGC操作。

「上圖能夠得出兩個結論:」

  • 在內存泄露的接口調用量很大的時候,如果恰好堆內老生代等其他情況一直不滿足FullGC條件,就一直不會FullGC,直接內存一路上漲。
  • 而在平時低調用量的情況下, 內存泄漏的比較慢,FullGC總會到來,回收掉泄露的那部分,這也是平時沒有出問題,正常運行了很久的原因。

「由于上面提到,我們進程的啟動參數中并沒有限制直接內存,于是我們將-XX:MaxDirectMemorySize配置加上,再次在沙箱環境進行了測驗。」

結果發現,進程占用的物理內存依然會不斷上漲,超出了我們設置的限制,“看上去”配置似乎沒起作用。

這讓我很訝異,難道JVM對內存的限制出現了問題?

「到了這里,能夠看出我排查過程中思路執著于直接內存的泄露,一去不復返了。」

「畫外音:我們應該相信JVM對內存的掌握,如果發現參數失效,多從自己身上找原因,看看是不是自己使用參數有誤。」

直接內存分析

為了更進一步的調查清楚直接內存里有什么,我開始對直接內存下手。由于直接內存并不能像堆內存一樣,很容易的看出所有占用的對象,我們需要一些命令來對直接內存進行排查,我有用了幾種辦法,來查看直接內存里到底出現了什么問題。

查看進程內存信息 pmap

pmap - report memory map of a process(查看進程的內存映像信息)

pmap命令用于報告進程的內存映射關系,是Linux調試及運維一個很好的工具。

  1. pmap -x pid 如果需要排序  | sort -n -k3** 

執行后我得到了下面的輸出,刪減輸出如下:

  1. .. 
  2. 00007fa2d4000000    8660    8660    8660 rw---   [ anon ] 
  3. 00007fa65f12a000    8664    8664    8664 rw---   [ anon ] 
  4. 00007fa610000000    9840    9832    9832 rw---   [ anon ] 
  5. 00007fa5f75ff000   10244   10244   10244 rw---   [ anon ] 
  6. 00007fa6005fe000   59400   10276   10276 rw---   [ anon ] 
  7. 00007fa3f8000000   10468   10468   10468 rw---   [ anon ] 
  8. 00007fa60c000000   10480   10480   10480 rw---   [ anon ] 
  9. 00007fa614000000   10724   10696   10696 rw---   [ anon ] 
  10. 00007fa6e1c59000   13048   11228       0 r-x-- libjvm.so 
  11. 00007fa604000000   12140   12016   12016 rw---   [ anon ] 
  12. 00007fa654000000   13316   13096   13096 rw---   [ anon ] 
  13. 00007fa618000000   16888   16748   16748 rw---   [ anon ] 
  14. 00007fa624000000   37504   18756   18756 rw---   [ anon ] 
  15. 00007fa62c000000   53220   22368   22368 rw---   [ anon ] 
  16. 00007fa630000000   25128   23648   23648 rw---   [ anon ] 
  17. 00007fa63c000000   28044   24300   24300 rw---   [ anon ] 
  18. 00007fa61c000000   42376   27348   27348 rw---   [ anon ] 
  19. 00007fa628000000   29692   27388   27388 rw---   [ anon ] 
  20. 00007fa640000000   28016   28016   28016 rw---   [ anon ] 
  21. 00007fa620000000   28228   28216   28216 rw---   [ anon ] 
  22. 00007fa634000000   36096   30024   30024 rw---   [ anon ] 
  23. 00007fa638000000   65516   40128   40128 rw---   [ anon ] 
  24. 00007fa478000000   46280   46240   46240 rw---   [ anon ] 
  25. 0000000000f7e000   47980   47856   47856 rw---   [ anon ] 
  26. 00007fa67ccf0000   52288   51264   51264 rw---   [ anon ] 
  27. 00007fa6dc000000   65512   63264   63264 rw---   [ anon ] 
  28. 00007fa6cd000000   71296   68916   68916 rwx--   [ anon ] 
  29. 00000006c0000000 4359360 2735484 2735484 rw---   [ anon ] 

可以看出,最下面一行是堆內存的映射,占用4G,其他上面有非常多小的內存占用,不過通過這些信息我們依然看不出問題。

堆外內存跟蹤 NativeMemoryTracking

Native Memory Tracking (NMT) 是Hotspot VM用來分析VM內部內存使用情況的一個功能。我們可以利用jcmd(jdk自帶)這個工具來訪問NMT的數據。

NMT必須先通過VM啟動參數中打開,不過要注意的是,打開NMT會帶來5%-10%的性能損耗。

  1. -XX:NativeMemoryTracking=[off | summary | detail] 
  2. off: 默認關閉 
  3. # summary: 只統計各個分類的內存使用情況. 
  4. # detail: Collect memory usage by individual call sites. 

然后運行進程,可以使用下面的命令查看直接內存:

  1. jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB] 
  2.   
  3. # summary: 分類內存使用情況. 
  4. # detail: 詳細內存使用情況,除了summary信息之外還包含了虛擬內存使用情況。 
  5. # baseline: 創建內存使用快照,方便和后面做對比 
  6. # summary.diff: 和上一次baseline的summary對比 
  7. # detail.diff: 和上一次baseline的detail對比 
  8. # shutdown: 關閉NMT 

我們使用:

  1. jcmd pid VM.native_memory detail scale=MB > temp.txt 

得到如圖結果:

 

上圖中給我們的信息,都不能很明顯的看出問題,至少我當時依然不能通過這幾次信息看出問題。

排查似乎陷入了僵局。

山重水復疑無路

在排查陷入停滯的時候,我們得到了來自WCS和SCF方面的回復,「兩方都確定了他們的封裝沒有內存泄漏的存在」,WCS方面沒有使用直接內存,而SCF雖然作為底層RPC協議,但是也不會遺留這么明顯的內存bug,否則應該線上有很多反饋。

查看JVM內存信息 jmap

此時,找不到問題的我再次新開了一個沙箱容器,運行服務進程,然后運行jmap命令,看一看JVM內存的「實際配置」:

  1. jmap -heap pid 

得到結果:

  1. Attaching to process ID 1474, please wait... 
  2. Debugger attached successfully. 
  3. Server compiler detected. 
  4. JVM version is 25.66-b17 
  5.  
  6. using parallel threads in the new generation. 
  7. using thread-local object allocation. 
  8. Concurrent Mark-Sweep GC 
  9.  
  10. Heap Configuration: 
  11.    MinHeapFreeRatio         = 40 
  12.    MaxHeapFreeRatio         = 70 
  13.    MaxHeapSize              = 4294967296 (4096.0MB) 
  14.    NewSize                  = 2147483648 (2048.0MB) 
  15.    MaxNewSize               = 2147483648 (2048.0MB) 
  16.    OldSize                  = 2147483648 (2048.0MB) 
  17.    NewRatio                 = 2 
  18.    SurvivorRatio            = 8 
  19.    MetaspaceSize            = 21807104 (20.796875MB) 
  20.    CompressedClassSpaceSize = 1073741824 (1024.0MB) 
  21.    MaxMetaspaceSize         = 17592186044415 MB 
  22.    G1HeapRegionSize         = 0 (0.0MB) 
  23.  
  24. Heap Usage: 
  25. New Generation (Eden + 1 Survivor Space): 
  26.    capacity = 1932787712 (1843.25MB) 
  27.    used     = 1698208480 (1619.5378112792969MB) 
  28.    free     = 234579232 (223.71218872070312MB) 
  29.    87.86316621615607% used 
  30. Eden Space
  31.    capacity = 1718091776 (1638.5MB) 
  32.    used     = 1690833680 (1612.504653930664MB) 
  33.    free     = 27258096 (25.995346069335938MB) 
  34.    98.41346682518548% used 
  35. From Space
  36.    capacity = 214695936 (204.75MB) 
  37.    used     = 7374800 (7.0331573486328125MB) 
  38.    free     = 207321136 (197.7168426513672MB) 
  39.    3.4349974840697497% used 
  40. To Space
  41.    capacity = 214695936 (204.75MB) 
  42.    used     = 0 (0.0MB) 
  43.    free     = 214695936 (204.75MB) 
  44.    0.0% used 
  45. concurrent mark-sweep generation: 
  46.    capacity = 2147483648 (2048.0MB) 
  47.    used     = 322602776 (307.6579818725586MB) 
  48.    free     = 1824880872 (1740.3420181274414MB) 
  49.    15.022362396121025% used 
  50.  
  51. 29425 interned Strings occupying 3202824 bytes 

輸出的信息中,看得出老年代和新生代都蠻正常的,元空間也只占用了20M,直接內存看起來也是2g...

嗯?為什么MaxMetaspaceSize = 17592186044415 MB?「看起來就和沒限制一樣」。

再仔細看看我們的啟動參數:

  1. -Xms4g -Xmx4g -Xmn2g -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80 

配置的是-XX:PermSize=256m -XX:MaxPermSize=512m,也就是永久代的內存空間。「而1.8后,Hotspot虛擬機已經移除了永久代,使用了元空間代替。」 由于我們線上使用的是JDK1.8,「所以我們對于元空間的最大容量根本就沒有做限制」,-XX:PermSize=256m -XX:MaxPermSize=512m 這兩個參數對于1.8就是過期的參數。

下面的圖描述了從1.7到1.8,永久代的變更:

 

「那會不會是元空間內存泄露了呢?」

我選擇了在本地進行測試,方便更改參數,也方便使用JVisualVM工具直觀的看出內存變化。

使用JVisualVM觀察進程運行

首先限制住元空間,使用參數-XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m,然后在本地循環調用出問題的接口。

得到如圖:

 

「可以看出,在元空間耗盡時,系統出發了Full GC,元空間內存得到回收,并且卸載了很多類。」

然后我們將元空間限制去掉,也就是使用之前出問題的參數:

  1. -Xms4g -Xmx4g -Xmn2g -Xss1024K -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80 -XX:MaxDirectMemorySize=2g -XX:+UnlockDiagnosticVMOptions 

得到如圖:

 

「可以看出,元空間在不斷上漲,并且已裝入的類隨著調用量的增加也在不斷上漲,呈現正相關趨勢。」

柳暗花明又一村

問題一下子明朗了起來,「隨著每次接口的調用,極有可能是某個類都在不斷的被創建,占用了元空間的內存」。

觀察JVM類加載情況 -verbose

在調試程序時,有時需要查看程序加載的類、內存回收情況、調用的本地接口等。這時候就需要-verbose命令。在myeclipse可以通過右鍵設置(如下),也可以在命令行輸入java -verbose來查看。

  1. -verbose:class 查看類加載情況 
  2. -verbose:gc 查看虛擬機中內存回收情況 
  3. -verbose:jni 查看本地方法調用的情況 

我們在本地環境,添加啟動參數-verbose:class循環調用接口。

可以看到生成了無數com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto:

  1. [Loaded com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto from file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar] 
  2. [Loaded com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto from file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar] 
  3. [Loaded com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto from file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar] 
  4. [Loaded com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto from file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar] 
  5. [Loaded com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto from file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar] 
  6. [Loaded com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto from file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar] 

當調用了很多次,積攢了一定的類時,我們手動執行Full GC,進行類加載器的回收,我們發現大量的fastjson相關類被回收。

「如果在回收前,使用jmap查看類加載情況,同樣也可以發現大量的fastjson相關類:」

  1. jmap -clstats 7984 

 

這下有了方向,「這次仔細排查代碼」,查看代碼邏輯里哪里用到了fastjson,發現了如下代碼:

  1. /** 
  2.  * 返回Json字符串.駝峰轉_ 
  3.  * @param bean 實體類. 
  4.  */ 
  5. public static String buildData(Object bean) { 
  6.     try { 
  7.         SerializeConfig CONFIG = new SerializeConfig(); 
  8.         CONFIG.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase; 
  9.         return jsonString = JSON.toJSONString(bean, CONFIG); 
  10.     } catch (Exception e) { 
  11.         return null
  12.     } 

問題根因

我們在調用wcs前將駝峰字段的實體類序列化成下劃線字段,**這需要使用fastjson的SerializeConfig,而我們在靜態方法中對其進行了實例化。SerializeConfig創建時默認會創建一個ASM代理類用來實現對目標對象的序列化。也就是上面被頻繁創建的類com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto,如果我們復用SerializeConfig,fastjson會去尋找已經創建的代理類,從而復用。但是如果new SerializeConfig(),則找不到原來生成的代理類,就會一直去生成新的WlkCustomerDto代理類。

下面兩張圖時問題定位的源碼:

我們將SerializeConfig作為類的靜態變量,問題得到了解決。

  1. private static final SerializeConfig CONFIG = new SerializeConfig(); 
  2.  
  3. static { 
  4.     CONFIG.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase; 

fastjson SerializeConfig 做了什么SerializeConfig介紹:

SerializeConfig的主要功能是配置并記錄每種Java類型對應的序列化類(ObjectSerializer接口的實現類),比如Boolean.class使用BooleanCodec(看命名就知道該類將序列化和反序列化實現寫到一起了)作為序列化實現類,float[].class使用FloatArraySerializer作為序列化實現類。這些序列化實現類,有的是FastJSON中默認實現的(比如Java基本類),有的是通過ASM框架生成的(比如用戶自定義類),有的甚至是用戶自定義的序列化類(比如Date類型框架默認實現是轉為毫秒,應用需要轉為秒)。當然,這就涉及到是使用ASM生成序列化類還是使用JavaBean的序列化類類序列化的問題,這里判斷根據就是是否Android環境(環境變量"java.vm.name"為"dalvik"或"lemur"就是Android環境),但判斷不僅這里一處,后續還有更具體的判斷。

理論上來說,每個SerializeConfig實例若序列化相同的類,都會找到之前生成的該類的代理類,來進行序列化。們的服務在每次接口被調用時,都實例化一個ParseConfig對象來配置Fastjson反序列的設置,而未禁用ASM代理的情況下,由于每次調用ParseConfig都是一個新的實例,因此永遠也檢查不到已經創建的代理類,所以Fastjson便不斷的創建新的代理類,并加載到metaspace中,最終導致metaspace不斷擴張,將機器的內存耗盡。

升級JDK1.8才會出現問題

導致問題發生的原因還是值得重視。為什么在升級之前不會出現這個問題?這就要分析jdk1.8和1.7自帶的hotspot虛擬機的差異了。

從jdk1.8開始,自帶的hostspot虛擬機取消了過去的永久區,而新增了metaspace區,從功能上看,metaspace可以認為和永久區類似,其最主要的功用也是存放類元數據,但實際的機制則有較大的不同。

首先,metaspace默認的最大值是整個機器的物理內存大小,所以metaspace不斷擴張會導致java程序侵占系統可用內存,最終系統沒有可用的內存;而永久區則有固定的默認大小,不會擴張到整個機器的可用內存。當分配的內存耗盡時,兩者均會觸發full gc,但不同的是永久區在full gc時,以堆內存回收時類似的機制去回收永久區中的類元數據(Class對象),只要是根引用無法到達的對象就可以回收掉,而metaspace判斷類元數據是否可以回收,是根據加載這些類元數據的Classloader是否可以回收來判斷的,只要Classloader不能回收,通過其加載的類元數據就不會被回收。這也就解釋了我們這兩個服務為什么在升級到1.8之后才出現問題,因為在之前的jdk版本中,雖然每次調用fastjson都創建了很多代理類,在永久區中加載類很多代理類的Class實例,但這些Class實例都是在方法調用是創建的,調用完成之后就不可達了,因此永久區內存滿了觸發full gc時,都會被回收掉。

而使用1.8時,因為這些代理類都是通過主線程的Classloader加載的,這個Classloader在程序運行的過程中永遠也不會被回收,因此通過其加載的這些代理類也永遠不會被回收,這就導致metaspace不斷擴張,最終耗盡機器的內存了。

這個問題并不局限于fastjson,只要是需要通過程序加載創建類的地方,就有可能出現這種問題。「尤其是在框架中,往往大量采用類似ASM、javassist等工具進行字節碼增強,而根據上面的分析,在jdk1.8之前,因為大多數情況下動態加載的Class都能夠在full gc時得到回收,因此不容易出現問題」,也因此很多框架、工具包并沒有針對這個問題做一些處理,一旦升級到1.8之后,這些問題就可能會暴露出來。

總結

問題解決了,接下來復盤下整個排查問題的流程,整個流程暴露了我很多問題,最主要的就是「對于JVM不同版本的內存分配還不夠熟悉」,導致了對于老生代和元空間判斷失誤,走了很多彎路,在直接內存中排查了很久,浪費了很多時間。

其次,排查需要的「一是仔細,二是全面,」,最好將所有可能性先行整理好,不然很容易陷入自己設定好的排查范圍內,走進死胡同不出來。

最后,總結一下這次的問題帶來的收獲:

JDK1.8開始,自帶的hostspot虛擬機取消了過去的永久區,而新增了metaspace區,從功能上看,metaspace可以認為和永久區類似,其最主要的功用也是存放類元數據,但實際的機制則有較大的不同。

對于JVM里面的內存需要在啟動時進行限制,包括我們熟悉的堆內存,也要包括直接內存和元生區,這是保證線上服務正常運行最后的兜底。

使用類庫,請多注意代碼的寫法,盡量不要出現明顯的內存泄漏。

對于使用了ASM等字節碼增強工具的類庫,在使用他們時請多加小心(尤其是JDK1.8以后)。

參考觀察程序運行時類加載的過程

blog.csdn.net/tenderhearted/article/details/39642275

Metaspace整體介紹(永久代被替換原因、元空間特點、元空間內存查看分析方法)

https://www.cnblogs.com/duanxz/p/3520829.html

java內存占用異常問題常見排查流程(含堆外內存異常)

https://my.oschina.net/haitaohu/blog/3024843

JVM源碼分析之堆外內存完全解讀

http://lovestblog.cn/blog/2015/05/12/direct-buffer/

JVM 類的卸載

https://www.cnblogs.com/caoxb/p/12735525.html

fastjson在jdk1.8上面開啟asm

https://github.com/alibaba/fastjson/issues/385

fastjson:PropertyNamingStrategy_cn

https://github.com/alibaba/fastjson/wiki/PropertyNamingStrategy_cn

警惕動態代理導致的Metaspace內存泄漏問題

https://blog.csdn.net/xyghehehehe/article/details/78820135

本文轉載自微信公眾號「后端技術漫談」,可以通過以下二維碼關注。轉載本文請聯系后端技術漫談公眾號。

 

責任編輯:武曉燕 來源: 后端技術漫談
相關推薦

2022-07-03 20:31:59

JVMJava虛擬機

2020-11-02 09:48:35

C++泄漏代碼

2022-09-21 08:39:52

堆外內存泄露內存分布

2022-06-15 16:04:13

Java編程語言

2022-02-08 17:17:27

內存泄漏排查

2019-02-20 09:29:44

Java內存郵件

2022-10-25 08:56:16

2023-01-04 18:32:31

線上服務代碼

2022-10-10 09:10:07

命令磁盤排查

2018-09-14 10:48:45

Java內存泄漏

2021-08-19 09:50:53

Java內存泄漏

2021-12-02 07:50:30

NFS故障內存

2018-07-03 10:49:22

性能故障排查

2017-01-11 14:02:32

JVM源碼內存

2018-07-20 08:44:21

Redis內存排查

2022-11-16 08:00:00

雪花算法原理

2019-09-10 10:31:10

JVM排查解決

2024-03-11 08:51:08

JVMSWAP內存

2022-12-17 19:49:37

GCJVM故障

2012-08-15 14:44:53

GC
點贊
收藏

51CTO技術棧公眾號

精品国产aⅴ| 国产不卡人人| 国产在线精品国自产拍免费| 久久天天躁狠狠躁夜夜av| 亚洲国产综合av| 欧美激情护士| 中文字幕在线不卡视频| 国产一区不卡在线观看| 在线免费a视频| 亚洲激情亚洲| 色综合亚洲精品激情狠狠| 日本美女视频网站| 国产成人免费9x9x人网站视频| 日本一区二区成人| 成人午夜在线观看| 亚洲国产精品成人无久久精品| 精品美女在线视频| 欧美午夜免费电影| 日日摸日日碰夜夜爽无码| 日本高清中文字幕在线| 久久天堂av综合合色蜜桃网| 91日韩在线播放| 精品成人无码久久久久久| 欧美国产三级| 精品国产一区二区三区四区在线观看 | 亚洲人午夜射精精品日韩| 久久精品国产一区二区三区免费看 | av免费看在线| 日本一区二区三区dvd视频在线| 国产成人看片| 国产强伦人妻毛片| 日韩国产欧美三级| 欧洲精品毛片网站| 国产精久久久久久| 午夜久久福利| 久久五月天综合| 激情无码人妻又粗又大| 欧美日本成人| 日韩国产精品亚洲а∨天堂免| 欧美精品色视频| 亚洲ww精品| 欧美色男人天堂| 亚洲中文字幕久久精品无码喷水| 9lporm自拍视频区在线| 亚洲午夜成aⅴ人片| 日韩视频在线免费播放| 日韩免费啪啪| 中文字幕亚洲区| 亚洲国产一区二区三区在线| 国产日韩精品在线看| 久久久国产午夜精品| 精品国产乱码久久久久久郑州公司| 国产成人麻豆精品午夜在线| 韩国v欧美v日本v亚洲v| 成人激情免费在线| 国产精品久久欧美久久一区| 久草精品在线观看| 成人亚洲欧美一区二区三区| 国产精品一二三四五区| 国产在线看一区| 91视频婷婷| 欧美自拍偷拍一区二区| 99精品久久免费看蜜臀剧情介绍| 精品国产_亚洲人成在线| 午夜影院在线视频| 2014亚洲片线观看视频免费| 欧美精品在线一区| 免费在线一级视频| 国产精品的网站| 成人在线观看www| 在线黄色网页| 香蕉久久一区二区不卡无毒影院| 奇米精品一区二区三区| 亚洲成人人体| 91精品欧美福利在线观看| 农村末发育av片一区二区| 韩国精品福利一区二区三区| 日韩电影免费观看中文字幕| 大黑人交xxx极品hd| 欧美艳星介绍134位艳星| 自拍偷拍亚洲区| 特级片在线观看| 亚洲男人影院| 国产日韩在线一区| 韩国av电影在线观看| 久久久久国产精品厨房| 亚洲在线不卡| 波多野结衣久久| 在线观看亚洲专区| 色黄视频免费看| 香蕉久久夜色精品国产使用方法| 国产亚洲一区精品| 精品无码久久久久久久久| 免费在线亚洲| 91系列在线播放| 天堂成人在线| 中文字幕av不卡| 国产美女主播在线播放| 高清在线一区| 亚洲精品久久久久中文字幕二区 | 亚洲欧洲色图综合| 亚洲精品蜜桃久久久久久| 影视一区二区三区| 精品国产一区二区三区av性色| 亚洲自拍偷拍一区二区| 亚洲电影在线一区二区三区| 日韩美女毛茸茸| 亚洲av无码片一区二区三区| 中文成人av在线| 毛片在线播放视频| 精品中文字幕一区二区三区四区 | 国产欧美日韩一区二区三区在线| 国产精品人成电影| 四虎在线视频免费观看| 国产精品久久久久一区二区三区 | 成av人片在线观看www| 欧美三级三级三级| 欧美bbbbb性bbbbb视频| 国产精品二区影院| 国产精品影片在线观看| 日韩欧美在线番号| 亚洲成a人在线观看| 国产精品v日韩精品v在线观看| 免费萌白酱国产一区二区三区| 久久久精品国产一区二区| 成人黄色激情视频| 91视频在线看| www.亚洲视频.com| 日本免费一区二区视频| 久久成年人免费电影| 波多野结衣高清在线| 99精品国产91久久久久久| 妺妺窝人体色www看人体| 动漫一区二区三区| 日韩在线视频国产| www.亚洲激情| 久久久精品国产免费观看同学| 丰满少妇久久久| www国产精品| 欧美激情视频一区二区三区不卡| 国产男女裸体做爰爽爽| 亚洲免费大片在线观看| 中文字幕色网站| 国产二区精品| 国产情人节一区| 一级毛片视频在线观看| 欧美色涩在线第一页| 极品蜜桃臀肥臀-x88av| 日产国产高清一区二区三区| 日韩欧美激情一区二区| 成人精品国产| 色爱精品视频一区| 6—12呦国产精品| 中文字幕一区免费在线观看| 亚洲欧美日韩精品一区| 亚州av乱码久久精品蜜桃| 成人日韩在线电影| 中文字幕中文字幕在线中高清免费版| 日韩一区二区免费在线电影| 久草免费新视频| 成人深夜福利app| 国产一区二区在线视频播放| 色综合久久中文| 日本久久久久久久久久久| 每日更新av在线播放| 欧美在线综合视频| 欧美性生给视频| 国产黑丝在线一区二区三区| 青春草国产视频| 亚洲图区在线| 国产在线精品播放| 青春草视频在线观看| 亚洲精品成人免费| 国产一区二区视频免费| 国产精品欧美一级免费| 欧美人与性动交α欧美精品| 伊人久久久大香线蕉综合直播| 免费毛片一区二区三区久久久| 日本精品在线中文字幕| 欧美成人激情在线| 天天操天天射天天| 在线观看日韩av先锋影音电影院| 国产人与禽zoz0性伦| 国产成人精品网址| 国产无套内射久久久国产| 成人羞羞网站入口| 国产高清精品一区| 日韩一区二区三区在线免费观看 | 欧美极品videos大乳护士| 中文字幕欧美专区| 亚洲欧美激情在线观看| 欧美亚洲一区三区| 日韩久久久久久久久| 国产精品久久久久久久第一福利| 伊人久久久久久久久| 久久久夜精品| 国产视频在线观看网站| 日韩免费高清| 国内精品久久久久久久果冻传媒| 国产成人福利夜色影视| 午夜精品一区二区三区在线视频| 99中文字幕一区| 日韩电影免费观看中文字幕| 国产乱码精品一区二三区蜜臂| 欧美日韩在线视频一区| 黑人操日本美女| 久久久亚洲欧洲日产国码αv| 国产农村妇女精品久久| 久久久久久黄| 黄色成人在线看| 自产国语精品视频| 亚洲精品一区二区三区蜜桃久 | 麻豆一区二区99久久久久| 日日摸日日碰夜夜爽无码| 小小影院久久| 亚洲精品中文综合第一页| 在线日韩网站| 国产欧美亚洲日本| 日本在线成人| 成人免费直播live| 99久久久国产精品免费调教网站| 久久久噜噜噜久久中文字免| 18网站在线观看| 最近中文字幕日韩精品| www在线免费观看| 亚洲美女av电影| 天堂网在线资源| 亚洲精品在线观看网站| 国产成人麻豆精品午夜在线 | 天天干,夜夜操| 精品乱人伦小说| 国产黄色av网站| 日韩一级完整毛片| 国产伦理吴梦梦伦理| 欧美日韩精品专区| 一级黄色片视频| 欧美日韩免费观看一区三区| 自拍偷拍18p| 日韩欧美主播在线| 一本一道无码中文字幕精品热| 午夜电影久久久| 国产精品30p| 亚瑟在线精品视频| 日本少妇在线观看| 婷婷久久综合九色综合伊人色| 国产亚洲第一页| 亚洲电影第三页| 一级免费在线观看| 黑人巨大精品欧美一区二区三区 | 国产日韩在线一区二区三区| 粉嫩久久久久久久极品| 国产日韩一区二区三区| 日韩三级视频| 日本在线观看一区二区三区| 欧美一级精品片在线看| 一区二区免费电影| 中文字幕人成人乱码| 免费看欧美一级片| 在线综合亚洲| 男人亚洲天堂网| 蜜臀久久久99精品久久久久久| 狠狠操狠狠干视频| 国产成人三级在线观看| 成年人的黄色片| 国产亚洲美州欧州综合国| 亚洲一级黄色录像| 1区2区3区欧美| 久久午夜鲁丝片午夜精品| 偷窥国产亚洲免费视频 | 91精品在线观看入口| 成人午夜免费在线观看| 日韩成人中文电影| 91高清在线视频| 欧美激情视频一区| 日韩成人影音| 成人黄色在线播放| 美国十次av导航亚洲入口| 日本一区美女| 中文字幕免费一区二区三区| 怡红院av亚洲一区二区三区h| 三级欧美韩日大片在线看| 亚洲精品免费一区亚洲精品免费精品一区| 精品一区二区三区av| 中文字幕一区二区人妻电影丶| 欧美激情一区二区三区不卡| 成年人二级毛片| 第一福利永久视频精品| 一本色道久久综合亚洲| 欧美成va人片在线观看| 国产小视频在线播放| 欧美人在线视频| 激情亚洲影院在线观看| 9a蜜桃久久久久久免费| 精品产国自在拍| 国产av熟女一区二区三区| 日本网站在线观看一区二区三区 | 久久久99久久精品欧美| 亚洲欧美小视频| 欧美性高潮在线| 亚洲第一天堂网| 中文字幕在线精品| h片在线观看视频免费| 国产一区二区在线播放| 一区二区导航| 国产一区二区三区小说| 久久精品国产一区二区三| avtt香蕉久久| 亚洲精品欧美激情| 这里只有精品国产| 亚洲精品mp4| 欧美xxxx性xxxxx高清| 成人精品福利视频| 欧美伦理在线视频| 国内自拍在线观看| 高清国产一区二区| 欧美h片在线观看| 欧美视频一区二区三区| 日本在线视频1区| 欧美激情一级精品国产| 四虎精品永久免费| 亚洲成人蜜桃| 日韩精品欧美精品| 法国伦理少妇愉情| 亚洲午夜电影在线观看| 亚洲精品国产一区二| 久久综合色88| 国产成人免费av一区二区午夜 | 免费黄色片网站| 欧美性少妇18aaaa视频| 人人妻人人澡人人爽精品日本| 精品视频9999| 韩国一区二区三区视频| 在线观看日韩片| 久久成人精品无人区| 国产精品视频在| 欧美日韩你懂的| 免费的黄网站在线观看| 在线看国产日韩| 成人av番号网| 99综合久久| 亚洲AV无码成人精品一区| 美女一区二区久久| 国产日韩精品中文字无码| 欧美探花视频资源| av在线首页| 成人网在线观看| 欧美国产另类| 老司机午夜免费福利| 精品magnet| 毛片网站在线| 国产精品www网站| 久久久影院免费| 欧美视频国产视频| 亚洲精品写真福利| 成人高潮片免费视频| 久久人人爽国产| 日本成人中文| 欧美亚洲日本在线观看| 中文字幕av一区 二区| 国产精品视频一区二区三区,| 久热精品视频在线观看| 视频精品一区| 国产精品沙发午睡系列| 久久久久一区二区三区四区| 五月激情丁香网| www.亚洲天堂| 成人午夜大片| 十八禁视频网站在线观看| 欧美激情一区不卡| www.国产三级| 欧美亚洲国产日本| 精品午夜久久| 中文字幕人妻熟女人妻a片| 亚洲一区二区视频| 欧美精品少妇| 91在线精品播放| 在线视频亚洲| 日韩亚洲欧美中文字幕| 精品国内片67194| 香蕉伊大人中文在线观看| 亚洲欧美国产精品桃花| 国产成人免费视频网站| 台湾佬中文在线| 欧美xxxx18国产| 亚洲人亚洲人色久| 宇都宫紫苑在线播放| 疯狂做受xxxx欧美肥白少妇| 五月天婷婷在线视频| 国产亚洲情侣一区二区无| 美女网站在线免费欧美精品| 激情视频在线播放| 伊人久久久久久久久久久| 日本久久伊人| 天天干天天干天天干天天干天天干| 一区二区三区免费看视频| 日韩a在线看| 国产精品国产三级国产专区53 | 性做久久久久久免费观看 | 亚洲区小说区图片区qvod| 亚洲男人天堂2021|