C#的lambda表達式的好用就不多說了,中午吃飯的時候突然想到一個以前(有年頭了,難道屌絲上歲數了就回憶這個么。。。)和同事爭執的坑。。
列個demo吧。。
先是一個類,這個類的對象就是為了吃堆內存用的,,
public class MemoryModel { public MemoryModel(int id) { Data = new byte[1024 * 1024]; Id = id; } public byte[] Data { set; get; } public int Id { set; get; } }
然后再來個類存放個事件
public class EventClass { public void Show(int m) { if (ShowMe != null) ShowMe(m); } public event Action<int> ShowMe; }
測試代碼如下;
EventClass e = new EventClass(); int i = 0; while (true) { List<MemoryModel> list = new List<MemoryModel>(); i++; for (int j = 0; j < 100; j++) { var mod = new MemoryModel(i); e.ShowMe += c => { string s = mod.Id + "----" + mod.Data.Length; Console.Write(c); }; list.Add(mod); } Thread.Sleep(50); list.Clear(); }
估計乍一看,不知所雲。。不明所以。其實主要想說的是事件注冊的這個lambda表達式,這塊存在比較大的問題,很多人為了方便會在lambda表達式內直接使用作用域范圍外的對象,比如說這個mod對象,委托也就是方法的引用,也可以說是方法的指針,運行時在執行方法時會打開棧幀,並將方法使用到的參數或參數的引用存儲到該棧幀的局部變量區中,此處我定義的事件目測只有一個int類型的參數,但由於這種隨意的編碼就導致了我附加了兩個參數,也就是mod對象。也就是說這個mod對象會被局部變量區持續引用也就發生了垃圾回收器無法對該對象進行回收了,直到EventClass對象釋放為止(當然此方法內是不會的。。)。結果也就內存泄漏了。。
當然場景不只是在這個while場景下,委托內使用作用域范圍外的對象都會增加那個對象的生命周期。。
對於這種情況發生的場景。。還是有一些的。。。