轉(zhuǎn)自: Imcache :一個(gè)Java新的緩存框架
堆Heap是內(nèi)存中動(dòng)態(tài)分配對象居住的地方镀裤。
如果使用new一個(gè)對象,它就被分配在堆內(nèi)存上缴饭。
這是相對于Stack暑劝,如果你有一個(gè)局部變量則它是位于Stack棧內(nèi)存空間。
BigMemory是用來避免GC對堆的開銷颗搂,從幾MB或GB大担猛。
BigMemory通過直接的ByteBuffers使用JVM進(jìn)程的內(nèi)存地址空間,不像其他原生Java對象接受GC管束丢氢。
EHCache(Terrcotta BigMemory)的 off-heap將你的對象從堆中脫離出來序列化毁习,然后存儲(chǔ)在一大塊內(nèi)存中,這就像它存儲(chǔ)到磁盤上上一樣卖丸,但它仍然在RAM中。
對象在這種狀態(tài)下不能直接使用盏道,它們必須首先反序列化稍浆。
也不受垃圾收集。序列化和反序列化會(huì)影響性能猜嘱。(FST-serialization還是很快)衅枫。
使用堆外內(nèi)存能夠降低GC導(dǎo)致的暫停。
應(yīng)用場景:
Session會(huì)話緩存朗伶,保存不激活的用戶session弦撩,比如用戶沒有正常退出,我們也無法確定他會(huì)不會(huì)短時(shí)間內(nèi)再回來论皆,將其會(huì)話存到堆外內(nèi)存益楼。一旦再次登錄,無需訪問數(shù)據(jù)庫可再次激活点晴。
計(jì)算結(jié)果的緩存感凤,大量查詢的結(jié)果等,擊中率比較低的都可以遷移到堆外粒督。
原文地址:http://www.infoq.com/cn/news/2014/12/external-memory-heap-memory/
一般情況下陪竿,Java中分配的非空對象都是由Java虛擬機(jī)的垃圾收集器管理的,也稱為堆內(nèi)內(nèi)存(on-heap memory)屠橄。
虛擬機(jī)會(huì)定期對垃圾內(nèi)存進(jìn)行回收族跛,在某些特定的時(shí)間點(diǎn),它會(huì)進(jìn)行一次徹底的回收(full gc)锐墙。
徹底回收時(shí)礁哄,垃圾收集器會(huì)對所有分配的堆內(nèi)內(nèi)存進(jìn)行完整的掃描,這意味著一個(gè)重要的事實(shí)——這樣一次垃圾收集對Java應(yīng)用造成的影響贮匕,跟堆的大小是成正比的姐仅。
過大的堆會(huì)影響Java應(yīng)用的性能。
對于這個(gè)問題,一種解決方案就是使用堆外內(nèi)存(off-heap memory)掏膏。
堆外內(nèi)存意味著把內(nèi)存對象分配在Java虛擬機(jī)的堆以外的內(nèi)存劳翰,這些內(nèi)存直接受操作系統(tǒng)管理(而不是虛擬機(jī))。
這樣做的結(jié)果就是能保持一個(gè)較小的堆馒疹,以減少垃圾收集對應(yīng)用的影響佳簸。
但是Java本身也在不斷對堆內(nèi)內(nèi)存的實(shí)現(xiàn)方式做改進(jìn)。
兩者各有什么優(yōu)缺點(diǎn)颖变?Vanilla Java博客作者Peter Lawrey撰寫了一篇文章生均,在文中他對三種方式:
用new來分配對象
對象池(object pool)
堆外內(nèi)存,
進(jìn)行了詳細(xì)的分析腥刹。
用new來分配對象內(nèi)存是最基本的一種方式马胧,Lawery提到:
在Java 5.0之前,分配對象的代價(jià)很大衔峰,以至于大家都使用內(nèi)存池佩脊。但是從5.0開始,對象分配和垃圾回收變得快多了垫卤,研發(fā)人員發(fā)現(xiàn)了性能的提升威彰,紛紛簡化他們的代碼,不再使用內(nèi)存池穴肘,而直接用new來分配對象歇盼。從5.0開始,只有一些分配代價(jià)較大的對象评抚,比如線程豹缀、套接字和數(shù)據(jù)庫鏈接,用內(nèi)存池才會(huì)有明顯的性能提升盈咳。
對于內(nèi)存池耿眉,Lawery認(rèn)為它主要用于兩類對象。
第一類是生命周期較短鱼响,且結(jié)構(gòu)簡單的對象鸣剪,在內(nèi)存池中重復(fù)利用這些對象能增加CPU緩存的命中率,從而提高性能丈积。
第二種情況是加載含有大量重復(fù)對象的大片數(shù)據(jù)筐骇,此時(shí)使用內(nèi)存池能減少垃圾回收的時(shí)間。對此江滨,Lawery還以StringInterner為例進(jìn)行了說明铛纬。
最后Lawery分析了堆外內(nèi)存,它和內(nèi)存池一樣唬滑,也能縮短垃圾回收時(shí)間告唆,但是它適用的對象和內(nèi)存池完全相反棺弊。內(nèi)存池往往適用于生命期較短的可變對象,而生命期中等或較長的對象擒悬,正是堆外內(nèi)存要解決的模她。
堆外內(nèi)存有以下特點(diǎn):
- 對于大內(nèi)存有良好的伸縮性
- 對垃圾回收停頓的改善可以明顯感覺到
- 在進(jìn)程間可以共享,減少虛擬機(jī)間的復(fù)制
Lawery還提到對外內(nèi)存最重要的還不是它能改進(jìn)性能懂牧,而是它的確定性侈净。
當(dāng)然堆外內(nèi)存也有它自己的問題,最大的問題就是你的數(shù)據(jù)結(jié)構(gòu)變得不那么直觀僧凤,如果數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜畜侦,就要對它進(jìn)行串行化(serialization),而串行化本身也會(huì)影響性能躯保。
另一個(gè)問題是由于你可以使用更大的內(nèi)存旋膳,你可能開始擔(dān)心虛擬內(nèi)存(即硬盤)的速度對你的影響了。
Lawery還介紹了OpenHFT公司提供三個(gè)開源庫:
Chronicle Queue途事、
Chronicle Map
Thread Affinity
這些庫可以幫助開發(fā)人員使用堆外內(nèi)存來保存數(shù)據(jù)溺忧。采用堆外內(nèi)存有很多好處,同時(shí)也帶來挑戰(zhàn)盯孙,
對堆外內(nèi)存感興趣的讀者可以閱讀Lawery的原文來了解更多信息。