本文概述
在平常場景進行發郵箱,短信以及APP 的推送消息一些特別活動。java
這種業務的特色是短期以內會有大量的用戶進入APP進行參與,這時候系統的壓力會忽然增長。面試
在業務流量高峯的時候,CPU的使用率十分十分高,而且直接致使系統卡死,沒法進行任何請求的處理,在系統重啓以後會好一段時間,可是後面又會立刻卡死。算法
經過這種思路排查,結果果真發現FULL GC的頻率十分高,竟然一分鐘一次FULL GC,頻率實在是過高了。數組
繼續排查發現使用jstat發現並不存在內存不合理的狀況,而且對象也是正常進入老年代,同時永久代的內存竟然也是正常的。緩存
這時候又會考慮一個問題,一分鐘一次FULL GC,證實老年代空間是不夠的,雖然新生代進入老年代是正常的,可是若是老年代 自己對象就很是多,會不會也會出現問題呢?按照這個思路繼續排查,果真發現老年代GC以後 竟然還有那麼多對象存活。併發
真相大白,緣由就是老年代被大量對象佔滿了,很容易觸發FULL GC,咱們可使用Jmap的工具排查這裏面的內容,固然,也可使用mat(memory anaylyze tool)進行排查,可是本文不涉及工具的使用介紹,大體介紹一下mat的處理流程:jvm
MAT的排查進程: jmap -dump:format=b,file=文件名[服務進程ID] 1. 首先內存快照,能夠看到當前內存狀況 2. 其次發現內存泄露 3. 建立的對象佔比量過大 4. 發現緣由是jvm緩存沒有及時進行清理,致使內存愈來愈大 5. 排查結果是本地內存沒有進行限制,同時沒有按期淘汰算法 6. 解決辦法使用一些EHCACASH的緩存便可
其實按照排查思路進行一步步排查,要找到問題其實並非很難。ide
String.split是如何形成內存泄露的 業務就直接跳過,這裏重點關注問題分析和解決流程。工具
不用說,標題已經暴露了一切,可是到底是如何分析出來的?這裏也不兜圈子,直接給一張圖,:測試
從這裏看到java.lang.Thread
的主線程main 線程,局部變量竟然佔用了**24.97%**的內存的對象。這裏告訴你問題出如今java.lang.Object[]
數組,這個數組佔用大量的內存。
在1的下面有一行藍色的 Details,進入以後能夠看到下面的內容:
在
Problem Supspect 3
裏面也能夠看到這裏面佔用了大量的String
對象。
從這裏能夠看到在main線程裏面,有一個arrayList集合佔用了幾乎全部的內存,這個List顯然也是Object[]的數組,而且在內容裏面存在Demo1$Data的對象實例。
從這個分析咱們知道了如何分析出內存佔用的問題,其實大膽猜想加上實用工具測試能夠基本均可以驗證出問題。
知道了佔用是由於Object[]數組的問題,接着來看下鏈路追蹤的狀況:
如上圖所示,咱們點擊statictrace進入到具體的代碼界面:
答案在最下面的圖:
咱們能夠明顯的看到是String的問題,經過代碼搜索發現有一個String.split
多是產生問題的緣由。
這裏就涉及一個JDK源代碼的問題了:
在JDK6的版本,一個字符串的底層是基於下面的形式進行存儲的,好比"yes yes yes yes"使用空格切分是以下的形式:
["yes","yes","yes","yes"]
可是到了Jdk7,他給每一個切分出來的字符串都建立了一個新的數組,意思就是說每次切分都切分出一個新的數組,這裏可能無法理解,因此咱們給出代碼:
if (xxxxx)// 一大堆判斷,不用管,總之大部分狀況你都會進這個If判斷 { return list.subList(0, resultSize).toArray(result); } return Pattern.compile(regex).split(this, limit);
這個sublist
毫無疑問就是罪魁禍首了,致使JDK版本升級了以後內存佔用爆高也是這個代碼,這個代碼幹了啥呢?
public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); }
這個也是典型的面試題,可用看到返回了當前List的視圖,同時這個視圖會隨着數組的改變而改變,關於這個對象細節百度一大堆,這裏不討論,這裏須要關注的是這個new
。
到這裏相信讀者也清楚爲何split()
方法會致使大量的Object[]
數組被構建出來,SubList
底層依然是一個數組!
說白了仍是代碼的質量問題,不用想能夠知道須要從代碼層面修復問題,解決fot循環裏面的split()
方法。
因此字符串的操做尤爲須要謹慎,由於字符串天生的不可變的特性,使用頻率很是高的同時也很容易出現問題。
總結: 這篇文章內容很少,主要爲下面兩個點: