Guava Cache系列之二:如何回收緩存

上一篇文章:Guava Cache系列之一:如何加載緩存

回收緩存方案

Guava Cache提供了三種基本的緩存回收方式:

  • 基于容量回收
  • 定時回收
  • 基于引用回收

1、基于容量的回收(size-based eviction)

緩存將嘗試回收最近沒有使用或總體上很少使用的緩存項?!?em>警告:在緩存項的數(shù)目達到限定值之前,緩存就可能進行回收操作——通常來說,這種情況發(fā)生在緩存項的數(shù)目逼近限定值時。


另外,不同的緩存項有不同的“權重”(weights)——例如,如果你的緩存值,占據(jù)完全不同的內存空間,你可以使用CacheBuilder.weigher(Weigher)指定一個權重函數(shù),并且用CacheBuilder.maximumWeight(long)指定最大總重。在權重限定場景中,除了要注意回收也是在重量逼近限定值時就進行了,還要知道重量是在緩存創(chuàng)建時計算的,因此要考慮重量計算的復雜度。

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
        .maximumWeight(100000)
        .weigher(new Weigher<Key, Graph>() {
            public int weigh(Key k, Graph g) {
                return g.vertices().size();
            }
        })
        .build(
            new CacheLoader<Key, Graph>() {
                public Graph load(Key key) { // no checked exception
                    return createExpensiveGraph(key);
                }
            });

2、定時回收(Timed Eviction)

CacheBuilder提供兩種定時回收的方法:

  • expireAfterAccess(long, TimeUnit):緩存項在給定時間內沒有被讀/寫訪問,則回收。請注意這種緩存的回收順序和基于大小回收一樣。
  • expireAfterWrite(long, TimeUnit):緩存項在給定時間內沒有被寫訪問(創(chuàng)建或覆蓋),則回收。如果認為緩存數(shù)據(jù)總是在固定時候后變得陳舊不可用,這種回收方式是可取的。

如下文所討論,定時回收周期性地在寫操作中執(zhí)行,偶爾在讀操作中執(zhí)行。

3、基于引用的回收(Reference-based Eviction)

通過使用弱引用的鍵、或弱引用的值、或軟引用的值,Guava Cache可以把緩存設置為允許垃圾回收。關于軟引用個弱引用的概念可以參考強引用、弱引用、軟引用、虛引用

  • CacheBuilder.weakKeys():使用弱引用存儲鍵。當鍵沒有其它(強或軟)引用時,緩存項可以被垃圾回收。因為垃圾回收僅依賴恒等式(==),使用弱引用鍵的緩存用==而不是equals比較鍵。
  • CacheBuilder.weakValues():使用弱引用存儲值。當值沒有其它(強或軟)引用時,緩存項可以被垃圾回收。因為垃圾回收僅依賴恒等式(==),使用弱引用值的緩存用==而不是equals比較值
  • CacheBuilder.softValues():使用軟引用存儲值。軟引用只有在響應內存需要時,才按照全局最近最少使用的順序回收。考慮到使用軟引用的性能影響,我們通常建議使用更有性能預測性的緩存大小限定(見上文,基于容量回收)。使用軟引用值的緩存同樣用==而不是equals比較值。

3、顯式清除

任何時候,你都可以顯式地清除緩存項,而不是等到它被回收:

清理什么時候發(fā)生?

  • 使用CacheBuilder構建的緩存不會"自動"執(zhí)行清理和回收工作,也不會在某個緩存項過期后馬上清理,也沒有諸如此類的清理機制。相反,它會在寫操作時順帶做少量的維護工作,或者偶爾在讀操作時做——如果寫操作實在太少的話。
  • 這樣做的原因在于:如果要自動地持續(xù)清理緩存,就必須有一個線程,這個線程會和用戶操作競爭共享鎖。此外,某些環(huán)境下線程創(chuàng)建可能受限制,這樣CacheBuilder就不可用了。
  • 相反,我們把選擇權交到你手里。如果你的緩存是高吞吐的,那就無需擔心緩存的維護和清理等工作。如果你的 緩存只會偶爾有寫操作,而你又不想清理工作阻礙了讀操作,那么可以創(chuàng)建自己的維護線程,以固定的時間間隔調用Cache.cleanUp()。ScheduledExecutorService可以幫助你很好地實現(xiàn)這樣的定時調度。

刷新

  • 刷新和回收不太一樣。正如LoadingCache.refresh(K)所聲明,刷新表示為鍵加載新值,這個過程可以是異步的。在刷新操作進行時,緩存仍然可以向其他線程返回舊值.
  • 而不像回收操作,讀緩存的線程必須等待新值加載完成。
  • 如果刷新過程拋出異常,緩存將保留舊值,而異常會在記錄到日志后被丟棄[swallowed]。

參考文章

CachesExplained

下一篇文章:Guava Cache系列之三:源碼分析

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • com.google.common.cache 1、背景 緩存,在我們日常開發(fā)中是必不可少的一種解決性能問題的方法...
    拾壹北閱讀 22,738評論 0 25
  • Google Guava Cache是一種非常優(yōu)秀本地緩存解決方案,提供了基于容量,時間和引用的緩存回收方式。基于...
    Acamy丶閱讀 26,317評論 3 34
  • 曉林Liu閱讀 191評論 0 1
  • 1. 控制車速 雨天路滑,視野不清,一定要控制車速,保持足夠的安全車距,平時經(jīng)常經(jīng)過的路段也不要大意。雨天突發(fā)情況...
    跑車的世界閱讀 379評論 0 0
  • 我們過的是以后,不是過從前。 翻了翻空間說說,發(fā)現(xiàn)自己以前是多傻逼,怎么會發(fā)這種說說照片。 下面評論的人早已沒有備...
    都樂很可愛閱讀 354評論 0 2

友情鏈接更多精彩內容