64位JDK應(yīng)用內(nèi)存問題
- 內(nèi)存回收導(dǎo)致的長時(shí)間停頓
- 現(xiàn)階段,64位JDK的性能測試結(jié)果普遍低于32位JDK
- 需要保證程序足夠穩(wěn)定,因?yàn)檫@種應(yīng)用要是產(chǎn)生堆溢出幾乎就無法產(chǎn)生堆轉(zhuǎn)儲(chǔ)快照(因?yàn)橐a(chǎn)生幾十GB乃至更大的Dump文件),哪怕產(chǎn)生了快照也幾乎無法進(jìn)行分析
- 相同程序在64位JDK消耗的內(nèi)存一般比32位JDK大,這是由于指針膨脹,以及數(shù)據(jù)類型對(duì)齊補(bǔ)白等因素導(dǎo)致的
集群優(yōu)化
- 盡量避免節(jié)點(diǎn)競爭全局的資源,最典型的就是磁盤競爭,各個(gè)節(jié)點(diǎn)如果同時(shí)訪問某個(gè)磁盤文件的話(尤其是并發(fā)寫操作容易出現(xiàn)問題),很容易導(dǎo)致IO異常
- 很難最高效率地利用某些資源池,譬如連接池,一般都是在各個(gè)節(jié)點(diǎn)建立自己獨(dú)立的連接池,這樣有可能導(dǎo)致一些節(jié)電池滿了而另外一些節(jié)點(diǎn)仍有較多空余。盡管可以使用集中式的JNDI,d但這個(gè)有一定復(fù)雜性并且有可能帶來額外的性能開銷
- 各個(gè)節(jié)點(diǎn)仍然不可避免地受到32位的內(nèi)存限制,在32位Windows平臺(tái)中每個(gè)進(jìn)程只能使用2GB的內(nèi)存,考慮到堆以外的內(nèi)存開銷,堆一般最多只能開到1.5GB。
- 大量使用本地緩存(如大量使用HashMap作為K/V緩存)的應(yīng)用,在邏輯集群中會(huì)造成較大的內(nèi)存浪費(fèi),因?yàn)槊總€(gè)邏輯節(jié)點(diǎn)上都有一份緩存,這時(shí)候可以考慮把本地緩存改為集中式緩存。
堆外內(nèi)存導(dǎo)致的溢出錯(cuò)誤
- Direct Memory:可通過-XX:MaxDirectMemorySize調(diào)整大小,內(nèi)存不足時(shí)拋出OutOfMemoryError或者OutOfMemoryError:Direct buffer memory
- 線程堆棧:可通過-Xss調(diào)整大小,內(nèi)存不足時(shí)拋出StackOverflowError(縱向無法分配,即無法分配新的棧幀)或者OutOfMemory:unable to create new native thread(橫向無法分配,即無法建立新的線程)
- Socket緩存區(qū):每個(gè)Socket連接都Receive和Send兩個(gè)緩存區(qū),分別占大約37KB和25KB內(nèi)存,連接多的話這塊內(nèi)存占用也比較可觀。如果無法分配,則可能會(huì)拋出IOException: too many open files異常
- JNI代碼:如果代碼中使用JNI調(diào)用本地庫,那本地庫使用的內(nèi)存也不在堆中
- 虛擬機(jī)和GC:虛擬機(jī)、GC的代碼執(zhí)行也要消耗一定的內(nèi)存
外部命令導(dǎo)致系統(tǒng)緩慢
如頻繁調(diào)用Java的Runtime.getRuntime().exec()方法
不恰當(dāng)數(shù)據(jù)結(jié)構(gòu)導(dǎo)致內(nèi)存占用過大
如HashMap<Long,Long>結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù)文件空間效率太低。
在HashMap<Long,Long>結(jié)構(gòu)中,只有key和value所存放的兩個(gè)長整型數(shù)據(jù)是有效數(shù)據(jù),共16B。這兩個(gè)長整型數(shù)據(jù)包裝成java.lang.Long對(duì)象之后,就分別具有8B的MarkWord、8B的Klass指針,在加8B存儲(chǔ)數(shù)據(jù)的long值。在這兩個(gè)Long對(duì)象組成Map.entry之后,又多了16B的對(duì)象頭。然后一個(gè)8B的next字段和4B的int型的hash字段,為了對(duì)齊,還必須添加4B的空白填充,最后還有HashMap中對(duì)這個(gè)Entry的8B引用,這樣增加兩個(gè)長整型數(shù)字,實(shí)際消耗的內(nèi)存為(Long(24B)*2)+Entry(32B)+Hash Ref(8B)=88B,空間效率為16B/88B=18%
調(diào)整內(nèi)存設(shè)置控制垃圾收集頻率
如eclipse啟動(dòng)時(shí),F(xiàn)ull GC大多數(shù)是由于老年代容量擴(kuò)展而導(dǎo)致的,由永久代空間擴(kuò)展導(dǎo)致的也有一部分。為了避免這些擴(kuò)展導(dǎo)致的性能浪費(fèi),我們可以把-Xms和-XX:PermSize參數(shù)值設(shè)置為-Xmx和-XX:MaxPermSize參數(shù)值一樣,這樣就強(qiáng)制虛擬機(jī)在啟動(dòng)時(shí)就把老年代和永久代的容量固定下來,避免運(yùn)行時(shí)自動(dòng)擴(kuò)展。