C#.NET4.0使用超大Dictionary內(nèi)存不足問題
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
最近需要實(shí)現(xiàn)將 XML 文件中存儲(chǔ)的數(shù)據(jù)統(tǒng)一讀取入內(nèi)存,并快速查詢指定數(shù)據(jù)的功能。當(dāng) XML 中的數(shù)據(jù)量不大時(shí),這個(gè)功能非常簡(jiǎn)單,選擇 Dictionary 數(shù)據(jù)結(jié)構(gòu),按鍵值對(duì)的方式存儲(chǔ)數(shù)據(jù)就好了,查詢也十分便捷。然而,我處理的 XML 數(shù)據(jù)小則幾百萬條,大則幾千萬條,使用傳統(tǒng)的方式在 .NET4.0 下會(huì)報(bào) “System.OutOfMemory” 的錯(cuò)誤。這主要是因?yàn)?.NET4.0 下有個(gè)硬性限制,單個(gè)對(duì)象不能超過 2G 。而在 .NET4.5 之后,則可以通過配置程序的 *.exe.config 文件開啟超大對(duì)象支持,來解決這個(gè)問題。當(dāng)然,必須保證你是 X64 的程序,并且物理內(nèi)存足夠。由于我的程序由于一些第三方開發(fā)庫限制,必須是基于 .NET4.0 ,雖然物理內(nèi)存足夠,這種方法并不適用。 研究了一下,最后我的解決方案還蠻 Tricky 的,分享給大家。 使用固定長(zhǎng)度的Dictionary 可變長(zhǎng)度的 Dictionary 在后臺(tái)實(shí)現(xiàn)時(shí),超過某個(gè)長(zhǎng)度就會(huì)自動(dòng)擴(kuò)展容量。當(dāng)數(shù)據(jù)量很大的時(shí)候,這個(gè)擴(kuò)容的過程非常耗費(fèi)時(shí)間和內(nèi)存,有時(shí)候甚至它會(huì)占用兩倍于當(dāng)前數(shù)據(jù)大小的內(nèi)存。為了避免這種問題,應(yīng)該使用定長(zhǎng)的 Dictionary ,防止它增長(zhǎng)。在我的程序中,最大可以將這個(gè)長(zhǎng)度設(shè)置為 4000000 。讀者可以按需調(diào)整。 // 示例: Dictionary<long, string> dic = new Dictionary<long, string>(4000000); 創(chuàng)建Dictionary列表對(duì)象 既然單個(gè)對(duì)象不能超過 2G ,那么可以使用多個(gè)對(duì)象拆分存儲(chǔ)不就好了。于是,我試著創(chuàng)建了幾個(gè) Dictionary 對(duì)象,當(dāng)前一個(gè) Dictionary 對(duì)象的長(zhǎng)度超過固定值時(shí),我就將后面的數(shù)據(jù)存儲(chǔ)在下一個(gè) Dictionary 對(duì)象中。經(jīng)過測(cè)試,這種方法是可行的。之所以說這個(gè)解決方案蠻 Tricky ,就是這個(gè)原因。 這里又引申出幾個(gè)問題,拆分成多少個(gè) Dictionary 對(duì)象合適?每個(gè)查詢數(shù)據(jù)的地方都需要寫循環(huán)查詢每個(gè) Dictionary 的代碼,比較冗余。于是,我將這種方法封裝成了一個(gè)單獨(dú)的類,重寫了添加、查詢的方法。我沒有寫刪除的方法,因?yàn)槲也恍枰獎(jiǎng)h除,有需求的讀者可以自己寫,比較簡(jiǎn)單。 類代碼如下,可參考。 public class NodeDicList { private int capacity; // 每個(gè)Dictionary的固定容量 public List<Dictionary<long, string>> dicList; public NodeDicList(int cap = 4000000) { capacity = cap; Dictionary<long, string> dic = new Dictionary<long, string>(cap); dicList = new List<Dictionary<long, string>>(); dicList.Add(dic); } // 統(tǒng)計(jì)列表總長(zhǎng)度 public int count() { int count = 0; foreach (Dictionary<long, string> dic in dicList) { count += dic.Count; } return count; } // 添加新數(shù)據(jù),會(huì)自動(dòng)創(chuàng)建新的Dictionary對(duì)象 public void addItem(long key, string p) { if (dicList.ElementAt(dicList.Count - 1).Count < capacity) { dicList.ElementAt(dicList.Count - 1).Add(key, p); } else { Dictionary<long, string> dic = new Dictionary<long, string>(capacity); dicList.Add(dic); dic.Add(key, p); } } // 查詢是否包含某個(gè)數(shù)據(jù) public bool containsKeyItem(long key) { foreach (Dictionary<long, string> dic in dicList) { if (dic.ContainsKey(key)) { return true; } } return false; } // 獲取某個(gè)數(shù)據(jù)的值 public string getItemByKey(long key) { foreach (Dictionary<long, string> dic in dicList) { if (dic.ContainsKey(key)) { return dic[key]; } } return null; } } 最后,如果你的對(duì)象不是 Dictionary ,是 Array 、List 等等,應(yīng)該都可以借鑒這個(gè)思路。
該文章在 2021/3/5 11:45:14 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |