记录一次缓存系统的优化过程
系統(tǒng)介紹:
之前線上跑著一個索引系統(tǒng),該索引系統(tǒng)主要功能將數(shù)據(jù)庫的數(shù)據(jù)取出來構(gòu)建成一個大的反向索引對象,存儲在本地cache中,然后供業(yè)務(wù)方進行查詢使用。該系統(tǒng)主要分為兩大模塊,一個為controller,一個為server。controller主要負責數(shù)據(jù)的更新操作,當數(shù)據(jù)更新后,廣播消息通知server并發(fā)送一個版本號newVersion(假設(shè)為newVersion=10)。server收到消息后,會獲取Redis的當前索引對應(yīng)的版本號curVersion,如果newVersion>curVersion,那么則說明需要重建索引,就會先加鎖(避免多臺同時構(gòu)建),然后加載數(shù)據(jù)并構(gòu)建索引,再將索引對象以及最新的版本號存儲到redis,更新本地cache中的索引對象,最后釋放鎖,如果加鎖失敗(說明有其他的機器在構(gòu)建索引了),則等待一段時間之后再重新獲取curVersion并newVersion比較。當newVersion<=curVersion,則直接從緩存中加載索引,更新到本地cache中
問題:
某天忽然有一臺server服務(wù)器出現(xiàn)了OOM異常,感覺很奇怪,通過使用jmap導(dǎo)出了堆信息,并通過MAT分析發(fā)現(xiàn),索引上有兩個對象引用的大小是一樣的,查看代碼發(fā)現(xiàn),原來在構(gòu)建索引對象時,為了使用方便,將一個對象賦值給了兩個引用,這種方式,在內(nèi)存中是占用一份數(shù)據(jù)的大小,不會有問題。然后序列化之后,再反序列化回來,就不是同一個對象了,在內(nèi)存中就會占用兩份數(shù)據(jù),這樣就會導(dǎo)致數(shù)據(jù)大小擴大了許多
改進:
找到了問題,就很好處理了,將重復(fù)的那個引用去掉,內(nèi)存占用立馬少了600多M
繼續(xù)改進:
由于索引數(shù)據(jù)中的很多字符串相同的,都是城市名字,但是對象從redis中取出來是通過反序列化實現(xiàn)的,無法使用inter()的方法來減少內(nèi)存的占用。后來在網(wǎng)上查到如果是G1垃圾收集器的話,可以使用-XX:+UseStringDeduplication來進行字符串排重,以下是排重后的效果圖,大概可以看出char數(shù)組由原來的429M減少到了82M多,注意UseStringDeduplication只會減少char數(shù)組的量
關(guān)于-XX:+UseStringDeduplication
在應(yīng)用程序啟動期間傳遞此JVM參數(shù)時,JVM將嘗試在垃圾收集過程中消除重復(fù)的字符串。在垃圾收集過程中,JVM會檢查內(nèi)存中的所有對象,因此作為該過程的一部分,它會嘗試識別它們中的重復(fù)字符串并嘗試消除它。
'-XX:+ UseStringDeduplication'消除了較長時間內(nèi)存在的重復(fù)字符串,對JavaWeb應(yīng)用程序進行的真實案例研究,當使用'-XX:+ UseStringDeduplication'時,該應(yīng)用程序沒有顯示任何內(nèi)存緩解。但是,如果您的應(yīng)用程序有很多緩存,那么'-XX:+ UseStringDeduplication'可能是有價值的(因為緩存對象通常往往是長期存在的對象)
'-XX:+ UseStringDeduplication'不會消除重復(fù)的字符串對象本身。它只替換了底層的char []。對String對象進行重復(fù)數(shù)據(jù)刪除在概念上只是對value字段的重新賦值,即aString.value = anotherString.value。
?注意:改參數(shù)只支持JDK8U20之后,垃圾收集是G1
?
轉(zhuǎn)載于:https://www.cnblogs.com/hello---word/p/11067148.html
總結(jié)
以上是生活随笔為你收集整理的记录一次缓存系统的优化过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CUDA杂谈
- 下一篇: windows自带反编译chm文件