在最近的公司框架開發中,利用了網上某大牛的反射緩存庫作為輔助。在測試的時候發現出現了巨大的內存泄露,在頻繁的操作后,內存不斷的產生巨大的開銷,10多分鍾就占有了5,6m的內存。解決問題的時,公司不能上網,沒有內存分析工具,沒有我鍾愛的ANTS Memory Profiler幫助下,我們只能靠簡單的內存輸出來二分查找縮小范圍,利用
System.Diagnostics命名空間下的Process的WorkingSet64屬性來統計兩次輸出的內存增長量(WorkingSet64:描述關聯的進程分配的物理內存量(以字節為單位))。花了半天終於定位到了第三方的緩存塊,一看嚇一跳居然緩存了2,3萬的對象。看到這里我很清楚的猜測到自定義緩存key一定沒有重寫來自Object的Equal方法,在三兩下很快解決了這次問題。哎,本不該相信第三方,剛開始還以為我數據綁定注冊的一大堆客戶端控件的事件引起的,但是我實現了IDisposable並取消了事件的,必究事件代理是強類型引用。
在這里我簡單說說這個本是基礎知識的東西。說道Equal,我們會聯想到==操作符,==對於值類型表示的是值相等,除string類型(內部重寫)外表示的是對象的引用,同一個引用地址才會相等。Equal描述的是對象的內容是否相等。但是在Object中默認實現是對引用reference的比較,我們要實現值的比較這必須重寫Equal方法和GetHashCode方法,這兩個是同時重寫的。在我們的IList.Contains,IDictionary.Contains中利用對象的比較就是默認的Equal方法比較,所以我們必須重寫這個方法,來達到我們實際的值比較。MSDN:Equals() 和運算符 == 的重寫准則(C# 編程指南)
然而在我們3.0后的表達式linq中對於對象的比較,我們需要實現的IEqualityComparer<T>接口,如下定義:
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer);
在微軟內部實現了5個重要的類,如下圖(圖來自博客園鶴沖天大牛):
在這里我不想在說很多,關於可以參見博客園鶴沖天大牛的c# 擴展方法奇思妙用基礎篇八:Distinct 擴展,何止 Linq 的 Distinct 不給力文章實戰。
最后給初學者提醒一句,對於IList.Contains,IDictionary.Contains注意實現Equal和GetHashCode,Linq比較IEqualityComparer<TSource>。
本不該錯的,應該是大牛忘寫了吧,可是害慘了我。

