Tôi hiểu những gì System.WeakReference làm, nhưng những gì tôi dường như không thể nắm bắt là một ví dụ thực tế về những gì nó có thể hữu ích cho. Bản thân lớp học dường như là tôi, một bản hack. Dường như với tôi rằng có những phương tiện khác, tốt hơn để giải quyết một vấn đề mà một WeakReference được sử dụng trong các ví dụ tôi đã nhìn thấy. Ví dụ kinh điển về nơi bạn thực sự đã sử dụng một WeakReference là gì? Không phải chúng tôi đang cố gắng để có được xa hơn cách loại hành vi này và sử dụng lớp học này?Sử dụng thực tế của System.WeakReference
Trả lời
Một ví dụ hữu ích là những kẻ chạy cơ sở dữ liệu hướng đối tượng db4o. Ở đó, WeakReferences được sử dụng như một loại bộ nhớ cache ánh sáng: nó sẽ giữ cho các đối tượng của bạn trong bộ nhớ chỉ miễn là ứng dụng của bạn làm, cho phép bạn đặt một bộ nhớ cache thực trên đầu trang.
Sử dụng khác sẽ là trong việc triển khai trình xử lý sự kiện yếu. Hiện tại, một nguồn rò rỉ bộ nhớ lớn trong các ứng dụng .NET là quên loại bỏ các trình xử lý sự kiện. Ví dụ.
public MyForm()
{
MyApplication.Foo += someHandler;
}
Xem sự cố? Trong đoạn mã trên, MyForm sẽ được lưu giữ trong bộ nhớ mãi mãi miễn là MyApplication vẫn còn trong bộ nhớ. Tạo 10 MyForms, đóng tất cả, 10 MyForms của bạn sẽ vẫn còn trong bộ nhớ, được giữ bởi trình xử lý sự kiện.
Nhập WeakReference. Bạn có thể xây dựng một trình xử lý sự kiện yếu bằng cách sử dụng WeakReferences để someHandler là một trình xử lý sự kiện yếu cho MyApplication.Foo, do đó sửa lỗi rò rỉ bộ nhớ của bạn!
Đây không chỉ là lý thuyết. Dustin Campbell từ blog DidItWith.NET đã đăng an implementation of weak event handlers bằng System.WeakReference.
tôi sử dụng nó để thực hiện một bộ nhớ cache nơi mục không sử dụng sẽ được tự động thu gom rác thải:
class Cache<TKey,TValue> : IEnumerable<KeyValuePair<TKey,TValue>>
{ Dictionary<TKey,WeakReference> dict = new Dictionary<TKey,WeakReference>();
public TValue this[TKey key]
{ get {lock(dict){ return getInternal(key);}}
set {lock(dict){ setInteral(key,value);}}
}
void setInteral(TKey key, TValue val)
{ if (dict.ContainsKey(key)) dict[key].Target = val;
else dict.Add(key,new WeakReference(val));
}
public void Clear() { dict.Clear(); }
/// <summary>Removes any dead weak references</summary>
/// <returns>The number of cleaned-up weak references</returns>
public int CleanUp()
{ List<TKey> toRemove = new List<TKey>(dict.Count);
foreach(KeyValuePair<TKey,WeakReference> kv in dict)
{ if (!kv.Value.IsAlive) toRemove.Add(kv.Key);
}
foreach (TKey k in toRemove) dict.Remove(k);
return toRemove.Count;
}
public bool Contains(string key)
{ lock (dict) { return containsInternal(key); }
}
bool containsInternal(TKey key)
{ return (dict.ContainsKey(key) && dict[key].IsAlive);
}
public bool Exists(Predicate<TValue> match)
{ if (match==null) throw new ArgumentNullException("match");
lock (dict)
{ foreach (WeakReference weakref in dict.Values)
{ if ( weakref.IsAlive
&& match((TValue) weakref.Target)) return true;
}
}
return false;
}
/* ... */
}
Tôi sử dụng tham chiếu yếu để giữ trạng thái trong hỗn hợp. Hãy nhớ rằng, mixins là tĩnh, vì vậy khi bạn sử dụng một đối tượng tĩnh để đính kèm nhà nước vào một không tĩnh, bạn không bao giờ biết nó sẽ được yêu cầu bao lâu. Vì vậy, thay vì giữ một số Dictionary<myobject, myvalue>
Tôi giữ một Dictionary<WeakReference,myvalue>
để ngăn không cho mixin kéo các vật quá lâu.
Vấn đề duy nhất là mỗi khi tôi truy cập, tôi cũng kiểm tra các tài liệu tham khảo đã chết và xóa chúng. Không phải là họ làm tổn thương bất cứ ai, trừ khi có hàng ngàn, tất nhiên.
Có hai lý do khiến bạn sử dụng WeakReference
.
Thay vì đối tượng toàn cầu khai báo là tĩnh: Tác phẩm toàn cầu được khai báo là static fields và các lĩnh vực tĩnh không thể GC'ed (thu gom rác) cho đến khi
AppDomain
là GC'ed. Vì vậy, bạn có nguy cơ ngoại lệ bộ nhớ ngoài. Thay vào đó, chúng ta có thể bọc đối tượng chung trong mộtWeakReference
. Mặc dùWeakReference
chính nó được khai báo tĩnh, đối tượng nó trỏ đến sẽ được GC 'khi bộ nhớ thấp.Về cơ bản, sử dụng
wrStaticObject
thay vìstaticObject
.class ThingsWrapper { //private static object staticObject = new object(); private static WeakReference wrStaticObject = new WeakReference(new object()); }
Ứng dụng đơn giản để chứng minh rằng đối tượng tĩnh được thu gom rác khi AppDomain là.
class StaticGarbageTest { public static void Main1() { var s = new ThingsWrapper(); s = null; GC.Collect(); GC.WaitForPendingFinalizers(); } } class ThingsWrapper { private static Thing staticThing = new Thing("staticThing"); private Thing privateThing = new Thing("privateThing"); ~ThingsWrapper() { Console.WriteLine("~ThingsWrapper"); } } class Thing { protected string name; public Thing(string name) { this.name = name; Console.WriteLine("Thing() " + name); } public override string ToString() { return name; } ~Thing() { Console.WriteLine("~Thing() " + name); } }
Lưu ý từ đầu ra dưới đây
staticThing
được GC'ed vào cuối, ngay cả sau khiThingsWrapper
là - ví dụ: GC'ed khiAppDomain
là GC'ed.Thing() staticThing Thing() privateThing ~Thing() privateThing ~ThingsWrapper ~Thing() staticThing
Thay vào đó, chúng tôi có thể quấn
Thing
trongWeakReference
. NhưwrStaticThing
có thể được GC'ed, chúng tôi sẽ cần một phương pháp lười biếng tải mà tôi đã bỏ ra cho ngắn gọn.class WeakReferenceTest { public static void Main1() { var s = new WeakReferenceThing(); s = null; GC.Collect(); GC.WaitForPendingFinalizers(); if (WeakReferenceThing.wrStaticThing.IsAlive) Console.WriteLine("WeakReference: {0}", (Thing)WeakReferenceThing.wrStaticThing.Target); else Console.WriteLine("WeakReference is dead."); } } class WeakReferenceThing { public static WeakReference wrStaticThing; static WeakReferenceThing() { wrStaticThing = new WeakReference(new Thing("wrStaticThing")); } ~WeakReferenceThing() { Console.WriteLine("~WeakReferenceThing"); } //lazy-loaded method to new Thing }
Lưu ý từ đầu ra bên dưới
wrStaticThing
là GC 'khi GC được gọi.Thing() wrStaticThing ~Thing() wrStaticThing ~WeakReferenceThing WeakReference is dead.
Đối với đối tượng là tốn nhiều thời gian để khởi tạo: Bạn không muốn đối tượng có thời gian consusming init được GC'ed. Bạn có thể giữ nguyên tham chiếu tĩnh để tránh điều đó (với khuyết điểm từ điểm trên) hoặc sử dụng
WeakReference
.
- 1. Cách sử dụng thực tế của Virtual Memory
- 2. sử dụng thực tế của IdentityHashMap trong Java 6
- 3. Sử dụng thực tế cây biểu thức
- 4. Sử dụng thực tế từ khóa `stackalloc`
- 5. jQuery .each() - Sử dụng thực tế?
- 6. Chữ ký thực tế sử dụng Reflection
- 7. Thực tế Sử dụng Traversal Cấp bậc
- 8. Thực tế tăng cường - Chỉ sử dụng GPS
- 9. Ví dụ thực tế về sử dụng NLTK
- 10. Sử dụng trong mua hàng cho hàng hóa thực tế
- 11. Sử dụng FileStream mà không cần tệp thực tế
- 12. Ma trận ba chiều: sử dụng thực tế
- 13. Sử dụng thực tế các chức năng đã kết hôn?
- 14. một số ứng dụng thực tế của mem_fn & bind
- 15. Sử dụng thực tế các sự kiện giao diện
- 16. Việc sử dụng GADT thực tế trên thế giới
- 17. Đặt ActiveRecord/Rails sử dụng cột mysql TIMESTAMP thực tế
- 18. Java Multi Threading - trường hợp sử dụng thực tế
- 19. Việc sử dụng các trường ẩn có thực tế không?
- 20. Có sử dụng thực tế nào của Garbage Collection của C++ 11 không?
- 21. Sử dụng thực tế từ khóa một phần trong C#
- 22. Việc sử dụng biến số thực tế là gì?
- 23. Sử dụng thực tế cờ bit trong .NET framework
- 24. Ví dụ thực tế của Idris
- 25. Ứng dụng Facebook thực tế chiều rộng
- 26. Hiệu ứng thực tế của viewPager.setOffscreenPageLimit (3) ;?
- 27. Cách sử dụng thực tế của một nhà xây dựng được bảo vệ là gì?
- 28. Hạn chế thực tế của bộ nhớ JVM và mức sử dụng CPU?
- 29. Ví dụ về sử dụng phổ biến, thực tế của sự kiện bong bóng và chụp?
- 30. Sử dụng các thành phần của khung công tác Zend mà không có khung thực tế?
+1 cho mẹo với người tổ chức sự kiện, điều đó thật tuyệt vời !!!! –
Vâng, nó khá tiện lợi. Chúng tôi đã áp dụng mã của anh ấy tại nơi làm việc, với một số bổ sung để xử lý các loại EventHandlers khác (ví dụ: EventHandler không chung, PropertyChangedEventHandler, v.v.). Nó làm việc rất tốt cho chúng tôi. –