小巧易於使用的有磁碟支援的ArrayList -Bozho的技術部落格

banq發表於2019-12-17

有時,列表List可能會變得太大而無法容納在記憶體中,因此您必須採取一些措施以避免記憶體不足。
做到這一點的正確方法是流傳輸–而不是將所有內容都放入記憶體中,您應該從源流傳輸資料並丟棄已經處理的條目。
但是,在某些情況下,超出程式碼控制一個列表範圍,但是不能使用流式傳輸。這些情況很少見,但萬一碰到,您必須找到解決方法。一種是重新實現程式碼以與流一起使用,但是根據編寫庫的方式,可能無法實現。因此,另一種選擇是使用磁碟支援的列表。
搜尋現有的解決方案會產生3年以上的庫包,例如這個這個這個
然後是MapDB,它很棒並且受支援。它主要是關於Map的,但是它也支援List,如此處所示

最後,如果您只需要迭代而幾乎不需要別的,則可以選擇自己實現一些簡單的事情。我在這裡做了– DiskBackedArrayList.java
它不支援上述庫包的很多功能,但最重要的是,它不支援隨機新增和隨機獲取,也不支援toArray()。它純粹是“填充列表”,然後“迭代列表”。它所依賴的ObjectOutputStream並不是十分高效,而是易於使用。請注意,在需要將少量資料新增到列表的情況下,我允許使用較短的記憶體prependList。
該列表將填充到記憶體中,直到達到指定的閾值,然後重新整理到磁碟,清除記憶體,記憶體又開始被填充。這也可能會更有效–在另一個執行緒中進行後臺重新整理,這不會干擾將元素新增到列表中,但是最佳化使事情變得複雜,在這種情況下,總執行時間不是問題。
最重要的是,該iterator()方法被覆蓋以返回一個自定義迭代器,該迭代器首先流式傳輸前置列表,然後從磁碟讀取所有內容,最後遍歷仍在記憶體中的最新批處理。最後,clear()應該最後呼叫該方法以關閉基礎流。可以在每次重新整理時開啟和關閉輸出流,但是ObjectOutputStream 由於某些特定於首先寫入標頭的實現,因此不能在附加模式下使用。

因此,基本上,我們將流方法隱藏在List介面下–它仍然是流元素,不需要時將其丟棄。理想情況下,應在資料來源(例如資料庫,訊息佇列等)上完成此操作,而不是將磁碟用作溢位空間,但是在某些情況下,使用磁碟很好。此實現是一個起點,因為尚未在生產中進行測試,但是說明您可以根據需要使現有類適應不同的資料訪問模式。
 

相關文章