線上堆內(nèi)存溢出和堆外內(nèi)存溢出問題的解決和思考

1.前言

由于項(xiàng)目的人員變動往核,接手了現(xiàn)在的項(xiàng)目荒典,項(xiàng)目前期的部署和試點(diǎn)運(yùn)營都沒有出現(xiàn)什么重大問題遗座,就在年初的項(xiàng)目全部鋪開的時(shí)候,由于并發(fā)量上來之后出現(xiàn)了頻繁的服務(wù)重啟的現(xiàn)象扼仲。后面經(jīng)過排查發(fā)現(xiàn)是內(nèi)存發(fā)生溢出導(dǎo)致的服務(wù)隔段時(shí)間就會重啟远寸。

在講內(nèi)存溢出之前先講回顧一些Java內(nèi)存結(jié)構(gòu):

    1)程序計(jì)數(shù)器:當(dāng)前字節(jié)碼所執(zhí)行的字節(jié)碼的行號指示器;

    2)Java虛擬機(jī)棧:線程私有屠凶,用于存儲局部變量驰后、操作棧、動態(tài)鏈接矗愧、方法出口等信息灶芝;

    3)本地方法棧:與虛擬機(jī)棧的區(qū)別就是虛擬機(jī)棧運(yùn)行的是Java方法,本地方法棧運(yùn)行的是本地方法唉韭;

    4)Java堆:存儲Java對象實(shí)例笙以;

    5)方法區(qū):線程共享活烙,存儲已經(jīng)被虛擬機(jī)加載的類信息割岛、常量籽慢、靜態(tài)變量、及時(shí)編譯器編譯后的代碼等數(shù)據(jù)住诸;

    6)運(yùn)行常量池:方法區(qū)的一部分驾胆,用于存放編譯期生成的各種字面量和符號引用涣澡。

    7)直接內(nèi)存:直接內(nèi)存的分配不會受到Java堆的限制,在Java1.4之后引入的一種基于通道和緩沖的方式丧诺,它可以使用Native方法分配堆外內(nèi)存入桂。

現(xiàn)場問題1

問題現(xiàn)象:

現(xiàn)場正常運(yùn)行一段時(shí)間之后服務(wù)就會發(fā)生重啟,并且發(fā)生的時(shí)候總是在訪問高峰期驳阎,一開始懷疑是內(nèi)存設(shè)置太锌钩睢(事實(shí)證明內(nèi)存也確實(shí)設(shè)置的小了),在調(diào)整內(nèi)存之后還是會發(fā)生服務(wù)重啟的現(xiàn)象搞隐。

排查思路:

這個(gè)時(shí)候意識到可能是內(nèi)存發(fā)生了溢出,于是增加gc日志(在虛擬機(jī)啟動參數(shù)中添加-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:home/ssd/log/gc.log -XX:GCLogFileSize=1024M參數(shù))远搪,運(yùn)行一段時(shí)間服務(wù)發(fā)生重啟劣纲,查看gc回收日志。gc日志在發(fā)生服務(wù)重啟的時(shí)候回收也是正常的谁鳍,設(shè)置的內(nèi)存并沒有消耗完全癞季。為了快速出現(xiàn)內(nèi)存溢出的現(xiàn)象,我們把內(nèi)存調(diào)整為1.5g倘潜,采用默認(rèn)的參數(shù)設(shè)置绷柒。

    如圖是發(fā)生內(nèi)存溢出gc的狀態(tài)圖:
image

Gc回收狀態(tài)圖,可以看到圈紅的地方是老年代的占用涮因,oc是分配的內(nèi)存废睦,ou是使用的內(nèi)存,還遠(yuǎn)沒有達(dá)到內(nèi)存的的設(shè)置閾值养泡。也可以查看更加詳細(xì)的gc信息嗜湃,由于內(nèi)存并未使用完全,因此回收細(xì)節(jié)就不再關(guān)注了澜掩。查看了gc日志购披,斷定服務(wù)重啟問題并不是堆內(nèi)存不足導(dǎo)致的。

為了驗(yàn)證我的猜想肩榕,我快速重啟服務(wù)之后監(jiān)控內(nèi)存增長并定時(shí)dump內(nèi)存快照刚陡,將內(nèi)存dump下來之后(jmap -dump:format=b,file=/home/ssd/log/Scheduler/java.dump pid)使用mat分析,發(fā)現(xiàn)內(nèi)存占用只用了50MB多株汉,這個(gè)這個(gè)時(shí)候懷疑是堆外內(nèi)存發(fā)生了溢出筐乳,于是就對堆外內(nèi)存進(jìn)行監(jiān)控。如圖為服務(wù)重啟前的內(nèi)存快照乔妈,堆內(nèi)存設(shè)置的1.5g哥童,服務(wù)重啟內(nèi)存的占用不到60MB:

image

到此為止已經(jīng)確認(rèn)是堆外內(nèi)存造成的,開始監(jiān)控堆外內(nèi)存占用褒翰。首先對vm參數(shù)添加-XX:NativeMemoryTracking=detail贮懈,表示詳細(xì)輸出堆外內(nèi)存占用匀泊,輸出指令jcmd ProsessPID VM.native_memory summary scale=MB《淠悖可以使用cron定時(shí)任務(wù)將輸出的結(jié)果輸出到對應(yīng)的文件中各聘,我是使用的Java定時(shí)任務(wù)將結(jié)果輸出到指定文件中分析,當(dāng)然也可以肉眼觀察變化抡医,使用Runtime調(diào)用服務(wù)指令輸出信息到文件躲因。如圖為其中一個(gè)時(shí)刻的堆外內(nèi)存占用圖,很明顯看到Thread占用異常忌傻,線程數(shù)占用到達(dá)了18610個(gè)大脉,并且還在不斷增長。

image

發(fā)現(xiàn)線程數(shù)量異常水孩,因此判斷內(nèi)存溢出極有可能是線程數(shù)增加導(dǎo)致內(nèi)存溢出镰矿,下一步就是找出產(chǎn)生異常線程的原因,通過堆棧信息發(fā)現(xiàn)在內(nèi)存溢出之前有大量的線程狀態(tài)都是wating狀態(tài)俘种,并且等待的都是同一把鎖秤标,迅速判斷這些線程都是什么線程,最后分析發(fā)現(xiàn)都是同一類線程宙刘,這些線程都有一個(gè)特點(diǎn):

image

這些線程等待的都是同一把鎖苍姜、而且都是同一個(gè)線程池產(chǎn)生的線程(這里還是吐槽一下之前的同事,為啥線程不加名字悬包。衙猪。。哈哈布近,誰讓他們增加了我的排查難度屈嗤。)。根據(jù)堆棧信息找到了鎖的位置吊输,發(fā)現(xiàn)是心跳處理線程饶号。線程不斷增長的原因是服務(wù)之間存在超時(shí)處理,由于我們服務(wù)是一個(gè)管理節(jié)點(diǎn)季蚂,有服務(wù)注冊中心功能茫船,其它服務(wù)注冊進(jìn)來的心跳超時(shí)時(shí)間是2s,注冊服務(wù)在2s之內(nèi)沒有收到心跳信息就會再次發(fā)出心跳請求扭屁,由于業(yè)務(wù)原因心跳必須一直保持算谈,如此不斷反復(fù)就導(dǎo)致了線程數(shù)量的增長。而在高峰期的時(shí)候由于訪問量增大料滥,心跳處理業(yè)務(wù)增加然眼,對于鎖的占用時(shí)間拉長,導(dǎo)致超時(shí)心跳增加葵腹,如此惡性循環(huán)高每。

首先解決心跳線程無限增長問題屿岂,心跳是通過thrift傳輸?shù)模覀冞@邊是服務(wù)端鲸匿,我們限制了服務(wù)端得到線程池大小爷怀,保證線程數(shù)量在可控范圍內(nèi);其次解決鎖的問題带欢,解決方案就是去鎖操作运授,鎖的對象是其他服務(wù)的運(yùn)行信息,采用的list結(jié)構(gòu)乔煞,后來決定采用map結(jié)構(gòu)吁朦,在不修改數(shù)據(jù)的情況下直接從內(nèi)存中獲取對象信息;最后就是解決耗時(shí)多的問題渡贾,這里沒有更好的辦法逗宜,就只能是每個(gè)處理邏輯的地方都加打印,找出耗時(shí)的地方剥啤,然后一個(gè)一個(gè)地優(yōu)化锦溪,優(yōu)化之后一個(gè)心跳的處理耗時(shí)減少到50ms以內(nèi)不脯,大大小于2s的超時(shí)設(shè)置府怯。

在解決這些問題值之后最內(nèi)存的大小也做了一些調(diào)優(yōu),服務(wù)運(yùn)行到現(xiàn)在就再也沒有發(fā)生重啟的問題了防楷。

現(xiàn)場問題2

這個(gè)現(xiàn)場問題比較簡單牺丙,只是堆內(nèi)存溢出,完全就是內(nèi)存不夠用導(dǎo)致的复局,在這里也總結(jié)一下排查思路冲簿。

這個(gè)集群的規(guī)模是比較小的規(guī)模,服務(wù)的內(nèi)存設(shè)置是1g亿昏,由于我們的業(yè)務(wù)模式的原因?qū)е旅看卧L問的數(shù)據(jù)的大小未做限制峦剔,為了保證處理速度我們會對消息進(jìn)行緩存,在處理的時(shí)候全部都是內(nèi)存處理角钩,原來是按照5k報(bào)文和20000條消息的緩存設(shè)置的內(nèi)存大小吝沫。一開始用戶也是按照這種限制來操作的,后來用戶對消息進(jìn)行打包處理递礼,每個(gè)請求由原來的1個(gè)報(bào)文合并到200個(gè)報(bào)文大小惨险,直接導(dǎo)致原來設(shè)置的內(nèi)存不夠用,導(dǎo)致的內(nèi)存不足溢出脊髓。

下面來看下排查過程辫愉,線上環(huán)境一直都沒有出現(xiàn)過問題,突然間就出現(xiàn)了內(nèi)存溢出的現(xiàn)象将硝,而且是頻繁的發(fā)生恭朗,幾乎是1分鐘內(nèi)就會發(fā)生一次屏镊,現(xiàn)場業(yè)務(wù)全部暫停,現(xiàn)場技術(shù)支持表示沒有任何改動冀墨。在接到這個(gè)問題之后第一時(shí)間就是觀察線上環(huán)境闸衫,使用jstat –gc pid 5000也是就是每5s輸出一次內(nèi)存回收信息,如圖1所示:

image

oc表示老年代的內(nèi)存大小诽嘉,ou表示老年代使用的內(nèi)存大小蔚出,可以看出老年代已經(jīng)滿了,此時(shí)可以確認(rèn)內(nèi)存不足導(dǎo)致虫腋,因此將內(nèi)存dump下來進(jìn)行分析骄酗,查看是什么占用了大量的內(nèi)存。如圖2所示悦冀,使用mat進(jìn)行分析:

image

經(jīng)過分析a占用了大部分內(nèi)存趋翻,而這部分正是我們緩存的消息數(shù)據(jù)。正好接近10000條消息盒蟆,因此我們懷疑是消息的數(shù)據(jù)太大導(dǎo)致的內(nèi)存不足踏烙。

為了驗(yàn)證我的猜想我在代碼中增加了對象大小的輸出RamUsageEstimator.sizeOf(),替換上去運(yùn)行一段時(shí)間之后發(fā)現(xiàn)有大量91032字節(jié)的對象历等,此時(shí)就可以完全判斷是由于對象太大導(dǎo)致的內(nèi)存溢出讨惩,在不影響運(yùn)行規(guī)格的情況下我們限制了緩存的大小為5000條,并且對報(bào)文大小進(jìn)行了控制寒屯,到此問題就算是完全解決了荐捻。

Java內(nèi)存思考

經(jīng)過上面的兩個(gè)問題,我重新思考了一下程序的內(nèi)存設(shè)置和一些邊界問題寡夹。

這里將Java內(nèi)存分為堆內(nèi)存(heap)和堆外內(nèi)存兩個(gè)部分处面。堆內(nèi)存是在虛擬機(jī)啟動的時(shí)候設(shè)置的虛擬機(jī)參數(shù),因此這部分內(nèi)存我們是很容器控制的菩掏,那么堆外內(nèi)存對于我們來說就相對更加隱蔽一些魂角,如果不是一些內(nèi)存限制嚴(yán)格或者堆外內(nèi)存溢出的情況發(fā)生,很難注意到這部分內(nèi)存智绸。那么什么是堆外內(nèi)存呢野揪?

與堆內(nèi)存對應(yīng),堆外內(nèi)存就是內(nèi)存對象分配在Java虛擬機(jī)的堆以外的內(nèi)存传于,這些內(nèi)存是直接從操作系統(tǒng)申請的囱挑。如我們經(jīng)常使用的java.nio.DirectByteBuffer類就是使用堆外內(nèi)存管理的,一些通信框架的內(nèi)存如netty也存在的堆外內(nèi)存沼溜;垃圾回收使用的一部分內(nèi)存也屬于堆外內(nèi)存平挑;線程占用的內(nèi)存;即時(shí)編譯器編譯之后的字節(jié)碼等都屬于堆外內(nèi)存管理。對于堆外內(nèi)存的監(jiān)控可以使用vm參數(shù)通熄,-XX:NativeMemoryTracking=detail唆涝,

輸入指令:

jcmd ProsessPID VM.native_memory summary scale=MB即可。輸出的數(shù)據(jù)如下圖:

image

可以看到整個(gè)memory主要包含了Java Heap唇辨、Class廊酣、Thread、Code赏枚、GC亡驰、Compiler、Internal饿幅、Other凡辱、Symbol、Native Memory Tracking栗恩、Arena Chunk這幾部分透乾;

其中reserved表示應(yīng)用可用的內(nèi)存大小,committed表示應(yīng)用正在使用的內(nèi)存大小

--Java Heap部分表示heap內(nèi)存目前占用了1536MB磕秤;

--Class部分表示已經(jīng)加載的classes個(gè)數(shù)為7472乳乌,其metadata占用了70MB;

--Thread部分表示目前有137個(gè)線程市咆,占用了137MB汉操;

--Code部分表示JIT生成的或者緩存的instructions占用了42MB;

--GC部分表示目前已經(jīng)占用了83MB的內(nèi)存空間用于幫助GC床绪;

--Internal部分表示命令行解析客情、JVMTI等占用了116MB其弊;

--Symbol部分表示諸如string table及constant pool等symbol占用了9MB癞己;

--Native Memory Tracking部分表示該功能自身占用了5MB;

Arena Chunk部分表示arena chunk占用了63MB,一個(gè)arena表示使用malloc分配的一個(gè)memory chunk梭伐,這些chunks可以被其他subsystems做為臨時(shí)內(nèi)存使用痹雅,比如pre-thread的內(nèi)存分配,它的內(nèi)存釋放是成bulk的糊识。commit是實(shí)際使用的內(nèi)存大小绩社。

堆內(nèi)存溢出問題比較容易排查,直接查看堆快照赂苗,找出占用內(nèi)存對象愉耙,很容易就可以找出溢出的原因;堆外內(nèi)存溢出問題比較難排查拌滋。

一個(gè)Java對象到底占用多大內(nèi)存

上面講到一個(gè)內(nèi)存計(jì)算組件RamUsageEstimator.sizeOf()朴沿,通過計(jì)算可以輸出單個(gè)對象占用的內(nèi)存大小,也可以采用openjdk的jol或者Instrumentation,那么一個(gè)Java對象占用的內(nèi)存大小是多少呢赌渣?Java對象內(nèi)存構(gòu)成是有三部分組成:

1)對象頭

Java對象頭由兩部分組成:一部分是Java對象運(yùn)行的數(shù)據(jù)(mark word)魏铅,比如hashCode、gc分帶年齡坚芜、鎖狀態(tài)標(biāo)志等览芳,這部分占用的內(nèi)存在32位虛擬機(jī)和64位虛擬機(jī)的大小分別是4B和8B;另一部分是Java對象指針(kclass)鸿竖,Java虛擬機(jī)通過這個(gè)指針判斷這個(gè)對象是哪個(gè)類的實(shí)例沧竟,如果是數(shù)組,對象頭中還必須有一塊表示數(shù)組大小的數(shù)據(jù)缚忧,因?yàn)镴ava虛擬機(jī)可以直接訪問對象元數(shù)據(jù)指導(dǎo)對象的大小屯仗,但是不能訪問數(shù)組的元數(shù)據(jù)來計(jì)算數(shù)組的大小。這部分大小在32位虛擬機(jī)和64位虛擬機(jī)的大小分別是4B和8B搔谴。

另外64位虛擬機(jī)中存在指針壓縮的問題魁袜,在閱讀elasticsearch官方文檔的時(shí)候有提到一個(gè)32g的概念,意思就是Java虛擬機(jī)的堆內(nèi)存申請?jiān)?2g以內(nèi)可以啟動指針壓縮達(dá)到節(jié)省空間的效果敦第,如果超過32g以上的指針壓縮就會失效峰弹,實(shí)際占用的內(nèi)存就會增多,也就是說超過32g的內(nèi)存不一定會比32g內(nèi)存存儲更多的對象芜果。

關(guān)于指針壓縮可以通過-XX:+UseCompressedOops來支持鞠呈,如果是打開的你們指針就會壓縮。

Java指針是用來存放內(nèi)存地址的右钾,在32位機(jī)器上內(nèi)存是通過一個(gè)32位二進(jìn)制數(shù)來存儲內(nèi)存地址蚁吝,操作系統(tǒng)中1個(gè)內(nèi)存單位長度是1byte=8bit,所以一個(gè)指針占用的內(nèi)存大小就是4個(gè)字節(jié)舀射,那么64位的二進(jìn)制數(shù)就是8個(gè)字節(jié)的大小窘茁。至于為什么是32g,主要原因是指針存儲的不再是內(nèi)存地址而是內(nèi)存地址的偏移量脆烟,所有在32g之前都是可以用32位指針表示的山林。

那么在使用指針壓縮的情況下,64位的對象頭就變成了12字節(jié)=Mark Work(8B) + kclass(4B).

2)實(shí)例數(shù)據(jù):

Java對象實(shí)例數(shù)據(jù)中有兩種:一種是8種基本類型邢羔;一種實(shí)例數(shù)據(jù)也是對象驼抹;

這里的實(shí)例變量要與棧中的實(shí)例變量進(jìn)行區(qū)分,Java棧里面保存的是局部變量表拜鹤、動態(tài)鏈接框冀、操作數(shù)棧、方法返回地址敏簿、附加信息明也,其中的局部變量表存儲的就是局部變量,而如果基本類型是對象 的實(shí)例變量則直接存儲到對象中,也就是堆內(nèi)存中诡右,當(dāng)然靜態(tài)變量final修飾的變量會存儲在方法區(qū)安岂。需要注意的是引用類型的大小是4字節(jié)。

3)對齊填充:

Java規(guī)定內(nèi)存對象的其實(shí)地址必須是8的倍數(shù)帆吻,因此對象的大小必須是8的倍數(shù)域那,舉個(gè)例子上面講的對象頭,通過指針壓縮之后的大小是12B猜煮,按照J(rèn)ava的規(guī)范次员,實(shí)際占用的內(nèi)存就是16B,不夠的部分就是進(jìn)行填充王带。數(shù)組由于存在一個(gè)數(shù)組大小的計(jì)算淑蔚,比普通對象多出4B,數(shù)組的對象頭為16B愕撰。

4)內(nèi)存計(jì)算實(shí)例

 public class ClassDemo {
    private boolean bo;
    private char ch;
    private int in;
    private float fl;
    private long lo;
    private double dou;

    public ClassDemo(boolean bo,char ch,int in,float fl,long lo,double dou) {
        this.bo = bo;
        this.ch = ch;
        this.in = in;
        this.fl = fl;
        this.lo = lo;
        this.dou = dou;
    }
}

內(nèi)存計(jì)算:1B(boolean)+2B(char)+4B(int)+4B(float)+8B(double)+8B(long)+12B(對象頭)=39B刹衫,再加上對齊的1B為40B,時(shí)間監(jiān)控結(jié)果也是符合我們的計(jì)算的搞挣。
如下結(jié)果:

    com.hikvision.cache.ClassDemo object internals:
     OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
          0     4           (object header)                           01 db ec 2d (00000001 11011011 11101100 00101101) (770497281)
          4     4           (object header)                           18 00 00 00 (00011000 00000000 00000000 00000000) (24)
          8     4           (object header)                           18 02 a7 16 (00011000 00000010 10100111 00010110) (380043800)
         12     4       int ClassDemo.in                              2
         16     8      long ClassDemo.lo                              3
         24     8    double ClassDemo.dou                             3.0
         32     4     float ClassDemo.fl                              3.0
         36     2      char ClassDemo.ch                              c
         38     1   boolean ClassDemo.bo                              false
         39     1           (loss due to the next object alignment)
    Instance size: 40 bytes

內(nèi)存溢出關(guān)注點(diǎn)主要有以下幾種:

1)堆內(nèi)存

可以通過-Xmx和-Xms參數(shù)控制带迟,如果堆內(nèi)存中沒有完成實(shí)例分配,并且堆內(nèi)存也無法擴(kuò)展囱桨,將會跑出OutOfMemoryError仓犬;

2)java虛擬機(jī)棧

棧內(nèi)存溢出有兩種情況:如果線程的棧深度大于虛擬機(jī)允許的深度,將拋出SrackOverFlowError異常舍肠;如果虛擬機(jī)可以動態(tài)擴(kuò)展搀继,當(dāng)擴(kuò)展無法盛情難到足夠的內(nèi)存是就會拋出StackOverflowError異常。

棧深度——虛擬機(jī)棧最多存儲的變量和計(jì)算結(jié)果值占用的深度大小翠语。

3)本地方法

本地方法會拋出StackOverflowError和OutOfMemoryError異常叽躯。

4)方法區(qū)

當(dāng)方法區(qū)無法分配內(nèi)存時(shí),將拋出OutOfMemoryError異常啡专。

5)Direct Memory

可以通過-XX:MaxDirectMemorySize調(diào)整大小险毁,內(nèi)存不足時(shí)拋出OutOfMemoryError或者OutOfMemoryError:Direct buffer memory

6)Socket 緩存區(qū)

java創(chuàng)建socket默認(rèn)的緩沖區(qū)也占用一定內(nèi)存(recieve和send分別默認(rèn)37k和25k)制圈,當(dāng)連接數(shù)多時(shí)無法分配會拋出IOException:Too many open files異常们童。

上面就是在發(fā)生兩次內(nèi)存溢出之后的總結(jié),后面也對邊界的一些問題進(jìn)行了修改以及對之前部分代碼進(jìn)行重構(gòu)鲸鹦,接口限流慧库,服務(wù)降級,線程池優(yōu)化等馋嗜。

關(guān)于實(shí)際項(xiàng)目接口和內(nèi)存的一些優(yōu)化和測試

1.1 接口性能測試

針對項(xiàng)目中的實(shí)時(shí)比對接口的性能較差的問題進(jìn)行了優(yōu)化齐板,接口通過批量的方式進(jìn)行處理,處理之后也是按照批量入庫的方式,在相同條件下的測試接口顯示甘磨,優(yōu)化后的接口耗時(shí)平均比優(yōu)化之后的1/4的耗時(shí)橡羞,性能提升大概是在75%左右。以上的測試結(jié)果的在正向測試得出的济舆。在模擬的環(huán)境下得出的結(jié)果卿泽,在實(shí)際項(xiàng)目中還有待驗(yàn)證,例如在cpu不足的情況下的耗時(shí)問題以及在內(nèi)存不足的情況下的耗時(shí)問題滋觉,以及在現(xiàn)場的環(huán)境下的耗時(shí)問題签夭。

下面是按照220個(gè)任務(wù)打包的測試數(shù)據(jù),數(shù)據(jù)使用從0開始持續(xù)派發(fā)任務(wù)到達(dá)數(shù)據(jù)庫限制閾值為止椎侠,表1 是原始的數(shù)據(jù)第租,圖1是兩份數(shù)據(jù)的折線圖,實(shí)際的比例大概是在1/4;性能提升較為明顯:

優(yōu)化之前:

提交測試用例總的次數(shù):1232次我纪;總耗時(shí):1661407慎宾;平均耗時(shí):1348.5ms。

優(yōu)化之后:

提交測試用例總的次數(shù):1232次浅悉;總的耗時(shí):422646璧诵;平均耗時(shí):343ms。

                              表1優(yōu)化前后數(shù)據(jù)統(tǒng)計(jì)
表1.PNG

如圖1位優(yōu)化前后面積圖仇冯,橫坐標(biāo)表示用例之宿,縱坐標(biāo)表示耗時(shí),單位ms苛坚。


圖1.png

具體修改點(diǎn)是將報(bào)文組裝進(jìn)行合并比被,在入庫的時(shí)候有原來的單個(gè)入庫改為批量入庫的方式。

1.2 內(nèi)存測試

1.2.1 內(nèi)存占用測試

內(nèi)存測試主要關(guān)注的是兩個(gè)方面泼舱,一個(gè)是內(nèi)存的限制大小和內(nèi)存占用的情況等缀;以上測試都是正向測試,采用的是模擬節(jié)點(diǎn)消費(fèi)任務(wù)娇昙,在調(diào)度占用內(nèi)存中尺迂,占用最大的還是任務(wù)節(jié)點(diǎn)的占用,因此冒掌,首先的測試維度就是報(bào)文大小對內(nèi)存占用的影響噪裕。

                   表2是在保留20000條任務(wù)的內(nèi)存占用情況:
表2.PNG

圖1是內(nèi)存占用的曲線圖,在實(shí)際的內(nèi)存占用中Java內(nèi)存的對象轉(zhuǎn)換和內(nèi)存對齊等原因會有一定的范圍波動股毫,總的來說有一種線性關(guān)系膳音,也就是說內(nèi)存占用跟任務(wù)的報(bào)文大小有直接關(guān)系。報(bào)文對應(yīng)內(nèi)存折線圖:固定變量:內(nèi)存保留20000條數(shù)據(jù)铃诬,內(nèi)存設(shè)置大小1.5G祭陷;近視關(guān)系如下:

y=38x+39

x:報(bào)文大胁粤荨;

y:占用內(nèi)存

                               圖2 報(bào)文大小和內(nèi)存占用的關(guān)系
圖2.jpg

隊(duì)列大小和內(nèi)存的關(guān)系也是一種線性關(guān)系兵志,表3和圖3位隊(duì)列大小對內(nèi)存占用的影響醇蝴。

                             表3 隊(duì)列大小對內(nèi)存內(nèi)存的影響
表3.PNG
                       圖3 任務(wù)隊(duì)列大小對內(nèi)存占用影響

隊(duì)列大小對內(nèi)存的影響:固定變量,1.5內(nèi)存想罕,10k報(bào)文大小;

近視關(guān)系:

y=0.021z-6

z:任務(wù)條數(shù)

y:內(nèi)存占用大小

實(shí)際測試中還測試了其它維度得到數(shù)據(jù)哑蔫,具體詳細(xì)數(shù)據(jù)可以查看測試文檔《內(nèi)存測試》。

以上內(nèi)存都是針對對內(nèi)存大小進(jìn)行測試弧呐,測試過程中也針對總的內(nèi)存進(jìn)行了監(jiān)控闸迷,具體數(shù)據(jù)在《內(nèi)存測試》中都有,可以自行觀察俘枫,總的來說這部分內(nèi)存占用變化不大腥沽,和內(nèi)存設(shè)置、線程數(shù)等有關(guān)鸠蚪。

在8g內(nèi)存情況下今阳,項(xiàng)目分配的內(nèi)存為4g,依照數(shù)據(jù)推算出的調(diào)度的內(nèi)存設(shè)置大小如下表:

堆內(nèi)存設(shè)置:1.5g茅信;隊(duì)列大小控制5000條盾舌;接口限制5并發(fā)(20個(gè)任務(wù)打包tps超過10000);

1.2.2 內(nèi)存回收測試

在內(nèi)存設(shè)置的情況下內(nèi)存回收頻率比較高蘸鲸,跟提交的任務(wù)的并發(fā)有關(guān)系妖谴;如圖5tps越大回收頻率越高。具體數(shù)據(jù)請參考《內(nèi)存測試》

                   圖4 內(nèi)存每s回收次數(shù)和tps之間的關(guān)系圖
圖4.jpg

參考:

《深入理解Java虛擬機(jī):Java高級特性與實(shí)戰(zhàn)》

《Java虛擬機(jī)實(shí)戰(zhàn)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酌摇,一起剝皮案震驚了整個(gè)濱河市膝舅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌窑多,老刑警劉巖仍稀,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異埂息,居然都是意外死亡技潘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門千康,熙熙樓的掌柜王于貴愁眉苦臉地迎上來享幽,“玉大人,你說我怎么就攤上這事吧秕×鹕粒” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵砸彬,是天一觀的道長颠毙。 經(jīng)常有香客問我,道長砂碉,這世上最難降的妖魔是什么蛀蜜? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮增蹭,結(jié)果婚禮上滴某,老公的妹妹穿的比我還像新娘。我一直安慰自己滋迈,他們只是感情好霎奢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饼灿,像睡著了一般幕侠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碍彭,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天晤硕,我揣著相機(jī)與錄音,去河邊找鬼庇忌。 笑死舞箍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的皆疹。 我是一名探鬼主播疏橄,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼略就!你這毒婦竟也來了软族?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤残制,失蹤者是張志新(化名)和其女友劉穎立砸,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體初茶,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颗祝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恼布。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片螺戳。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖折汞,靈堂內(nèi)的尸體忽然破棺而出倔幼,到底是詐尸還是另有隱情,我是刑警寧澤爽待,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布损同,位于F島的核電站翩腐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏膏燃。R本人自食惡果不足惜茂卦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一组哩、第九天 我趴在偏房一處隱蔽的房頂上張望等龙。 院中可真熱鬧伶贰,春花似錦、人聲如沸黍衙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽们豌。三九已至,卻和暖如春障癌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辩尊。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工涛浙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摄欲。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像我注,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子但骨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353