當前位置:
首頁 > 知識 > 如何通過軟引用和弱引用提升JVM內存使用性能

如何通過軟引用和弱引用提升JVM內存使用性能

初學者或初級程序員在面試時如果能證明自己具有分析內存用量和內存調優的能力,這相當有利,因為這是針對5年左右相關經驗的高級程序員的要求。而對於高級程序員來說,如果能在面試時讓面試官感覺你確實做過內存調優的工作,那麼面試官很有可能不問Java Core部分的其它問題了,畢竟虛擬機調優是Java Core部分非常資深的知識點。

在Java對象里,有強弱軟虛四種引用,它們都和垃圾回收流程密切相關,在項目里,我們可以通過合理地使用不同類型的引用來優化代碼的內存使用性能。

指向通過new得到的內存空間的引用叫強引用。比如有String a = newString(「123」);其中的a就是一個強引用,它指向了一塊內容是123的堆空間。

平時我們用的最多的引用就是強引用,以至於很多人還不知道有其他類型引用的存在,下面我們來說下弱軟虛這三種平時不常見(但在關鍵時刻不可替代)的用途。

一、軟引用和弱引用的用法

軟引用(SoftReference)的含義是,如果一個對象只具有軟引用,而當前虛擬機堆內存空間足夠,那麼垃圾回收器就不會回收它,反之就會回收這些軟引用指向的對象。

弱引用(WeakReference)與軟引用的區別在於,垃圾回收器一旦發現某塊內存上只有弱引用(一定請注意只有弱引用,沒強引用),不管當前內存空間是否足夠,那麼都會回收這塊內存。

通過下面的ReferenceDemo.java,我們來看下軟引用和弱引用的用法,並對比一下它們的差別。

在第7行里,我們定義了SoftReference<String>類型的軟引用softRef,用來指向第7行通過new創建的空間,在第14行,我 們是通過弱引用weakRef指向第13行創建的空間。

接下來我們通過下表來觀察下具體針對內存空間的操作:

二、軟引用的使用場景

比如在一個博客管理系統里,為了提升訪問性能,在用戶在點擊博文時,如果這篇博文沒有緩存到內存中,則需要做緩存動作,這樣其它用戶在點擊同樣這篇文章時,就能直接從內存里裝載,而不用走資料庫,這樣能降低響應時間。

我們可以通過資料庫級別的緩存在做到這點,這裡也可以通過軟引用來實現,具體的實現步驟如下:

1、可以通過定義Content類來封裝博文的內容,其中可以包括文章ID、文章內容、作者、發表時間和引用圖片等相關信息。

2、可以定義一個類型為HashMap<String, SoftReference<Content>>的對象類保存緩存內容,其中鍵是String類型,表示文章ID,值是指向Content的軟引用。

3、當用戶點擊某個ID的文章時,根據ID到第二步定義的HashMap里去找,如果找到,而且所對應的SoftReference<Content>值內容不是null,則直接從這裡拿數據並做展示動作,這樣不用走資料庫,可以提升性能。

4、如果用戶點擊的某個文章的ID在HashMap里找不到,或者雖然找到,但對應的值內容是空,那麼就從資料庫去找,找到後顯示這個文章,同時再把它插入到HashMap里,這裡請注意,顯示後需要撤銷掉這個Content類型對象上的強引用,保證它上面只有一個軟引用。

來分析下用軟引用有什麼好處?

假設我們用1個G的空間緩存了10000篇文章,這10000篇文章所佔的內存空間上只有軟引用。如果內存空間足夠,那麼我們可以通過緩存來提升性能,但萬一內存空間不夠,我們可以依次釋放這10000篇文章所佔的1G內存,釋放後不會影響業務流程,最多就是降低些性能。

對比一下,如果我們這裡不用軟應用,而是用強引用來緩存,由於不知道文章何時將被點擊,我們還無法得知什麼時候可以撤銷這些文章對象上的強引用,或者即使我們引入了一套緩存淘汰流程,但這就是額外的工作了,這就沒剛才使用「軟引用「那樣方便了。

三、通過WeakHashMap來了解弱引用的使用場景

WeakHashMap和HashMap很相似,可以存儲鍵值對類型的對象,但我們可以從它的名字上看出,其中的引用是弱引用。通過下面的WeakHashMapDemo.java,我們來看下它的用法。

通過下表,我們來詳細說明關鍵代碼的含義:

根據上文和這裡的描述,我們知道如果當一個對象上只有弱引用時,這個對象會在下次垃圾回收時被回收,下面我們給出一個弱引用的使用場景。

比如在某個電商網站項目里,我們會用Coupan這個類來保存優惠券信息,在其中我們可以定義優惠券的打折程度,有效日期和所作用的商品範圍等信息。當我們從資料庫里得到所有的優惠券信息後,會用一個List<Coupan>類型的coupanList對象來存儲所有優惠券。

而且,我們想要用一種數據結構來保存一個優惠券對象以及它所關聯的所有用戶,這時我們可以用WeakHashMap<Coupan, List<WeakReference<User>>>類型的weakCoupanHM對象。其中它的鍵是Coupan類型,值是指向List<User>用戶列表的弱引用。

大家可以想像下,如果有100個優惠券,那麼它們會存儲於List<Coupan>類型的coupanList,同時,WeakHashMap<Coupan, List<WeakReference<User>>>類型的weakCoupanHM對象會以鍵的形式存儲這100個優惠券。而且,如果有1萬個用戶,那麼我們可以用List<User>類型的userList對象來保存它們,假設coupan1這張優惠券對應著100個用戶,那麼我們一定會通過如下的代碼存入這種鍵值對關係,weakCoupanHM.put(coupan1,weakUserList);,其中weakUserList里以弱引用的方式保存coupan1所對應的100個用戶。

這樣的話,一旦當優惠券或用戶發生變更,它們的對應關係就能自動地更新,具體表現如下:

1、當某個優惠券(假設對應於coupan2對象)失效時,我們可以從coupanList里去除該對象,coupan2上就沒有強引用了,只有weakCoupanHM對該對象還有個弱引用,這樣coupan2對象能在下次垃圾回收時被回收,從而weakCoupanHM里就看不到了。

2、假設某個優惠券coupan3用弱引用的方式指向於100個用戶,當某個用戶(假設user1)註銷賬號時,它會被從List<User>類型的userList對象中被移除。這時該對象上只有weakCoupanHM里的值(也就是List<WeakReference<User>>)這個弱引用,該對象同樣能在下次垃圾回收時被回收,這樣coupan3的關聯用戶就會自動地更新為99個。

如果不用弱引用,而是用常規的HashMap<Coupan,List<User>>來保存對應關係的話,那麼一旦出現優惠券或用戶的變更的話,那麼我們就不得不手動地更新這個表示對應關係的HashMap對象了,這樣,代碼就會變得複雜,而且我們很有可能因疏忽而忘記在某個位置添加更新代碼。相比之下,弱引用給我們帶來的「自動更新「就能給我們帶來很大的便利。

四、不能投機取巧,但面試確實有技巧

我的意思不是讓大家投機取巧,事實上,如果大家只知道這些知識,而不知道其他虛擬機(或Java Core)相關的知識點,面試通過的可能性很低。

但話說回來,如果大家在平時開發時積累了很多經驗,但不會總結,在面試時也無法很好地展示各種能力,這樣也是非常可惜的。

如何通過軟引用和弱引用提升JVM內存使用性能

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

基於Crypto++密碼庫的ECIES和ECDSA演算法的聯合使用
正則表達式

TAG:程序員小新人學習 |