强引用与弱引用
面试题
- 什么是强引用和弱引用?
强引用是默认的对象引用方式,会阻止GC回收对象;弱引用则允许GC在需要时回收对象,不会阻止垃圾回收。
- 什么时候应该使用弱引用?
适合使用弱引用的场景包括:缓存系统、事件订阅、对象生命周期跟踪等需要引用对象但又不希望阻止其被回收的情况。
- 如何检查弱引用对象是否还存在?
可以通过WeakReference的IsAlive属性检查,或使用TryGetTarget方法尝试获取目标对象。
- 弱引用有什么性能影响?
弱引用有轻微的性能开销,因为每次访问都需要检查对象是否存活。因此高频访问的数据更适合强引用结合缓存过期策略。
- 什么是ConditionalWeakTable?
ConditionalWeakTable是一种特殊容器,它以弱引用方式持有键(Key),使得元数据(Value)的生命周期与键严格绑定,常用于为对象附加元数据。
- 强引用是默认引用方式,会阻止GC回收对象,适用于需要严格控制生命周期的核心对象
- 弱引用不会阻止GC回收对象,适用于缓存、事件订阅等需要灵活内存管理的场景
- 使用弱引用时,每次访问都需要检查对象是否存活
- 弱引用有自己的开销,对小对象可能不划算
- 合理运用这两种机制可以显著提升应用程序的稳定性和性能
强引用(Strong Reference)
- 强引用是C#中最常见的引用类型,也是默认的引用方式。
- 强引用会保持对象的引用,只要强引用存在,垃圾回收器(GC)便不会回收该对象。
- 当对象被强引用时,引用计数会增加
- 长生命周期的强引用(如静态字段)可能导致内存泄漏
代码示例
// 创建一个强引用
var myObject = new MyClass();
// 只要myObject在作用域内,MyClass对象就不会被GC回收
弱引用(Weak Reference)
-
弱引用是一种特殊引用类型,它不会阻止对象被垃圾回收器回收。
-
当对象只有弱引用时,GC可以随时回收它。
-
不会阻止对象被垃圾回收
-
不会增加对象的引用计数
-
适用于缓存、事件订阅等场景,避免内存泄漏
-
每次访问弱引用时需检查对象是否存活
代码示例
// 创建一个对象
var myObject = new MyClass();
// 创建弱引用
WeakReference weakRef = new WeakReference(myObject);
// 解除强引用
myObject = null;
// 通过弱引用访问对象
if (weakRef.IsAlive)
{
var obj = weakRef.Target as MyClass;
obj.DoSomething();
}
else
{
Console.WriteLine("对象已被回收");
}
强引用与弱引用的对比
| 特性 | 强引用 | 弱引用 |
|---|---|---|
| 阻止GC回收 | 是 | 否 |
| 默认引用方式 | 是 | 否 |
| 引用计数影响 | 增加 | 不影响 |
| 适用场景 | 核心对象管理 | 缓存、事件订阅 |
| 访问方式 | 直接访问 | 需检查IsAlive或TryGetTarget |
| 性能影响 | 无额外开销 | 有轻微检查开销 |
弱引用的使用场景
缓存系统
弱引用非常适合用于实现缓存,特别是大型数据对象(如图片、文件等)的缓存。
当内存压力大时,GC可以自动回收这些对象。
public class ImageCache
{
private readonly Dictionary<string, WeakReference<Bitmap>> _cache = new();
public Bitmap GetImage(string path)
{
if (_cache.TryGetValue(path, out var weakRef) && weakRef.TryGetTarget(out Bitmap image))
{
return image; // 直接返回缓存对象
}
else
{
image = LoadBitmapFromDisk(path); // 重新加载
_cache[path] = new WeakReference<Bitmap>(image);
return image;
}
}
}
弱事件模式
在事件驱动编程中,事件的订阅可能导致订阅者无法被回收,从而引发内存泄漏。
弱事件模式可以解决这个问题。
public class EventPublisher
{
public event EventHandler<EventArgs> DataUpdated;
public void RaiseEvent()
{
DataUpdated?.Invoke(this, EventArgs.Empty);
}
}
public class EventSubscriber
{
public EventSubscriber(EventPublisher publisher)
{
// 弱事件订阅
WeakEventManager<EventPublisher, EventArgs>.AddHandler(
publisher,
nameof(EventPublisher.DataUpdated),
OnDataUpdated
);
}
private void OnDataUpdated(object sender, EventArgs e)
{
// 处理事件逻辑
}
}
元数据管理
使用ConditionalWeakTable可以为对象附加元数据且不影响其生命周期。
public static class ObjectMetadataExtension
{
private static readonly ConditionalWeakTable<object, Metadata> _metadataTable = new();
public static void SetMetadata(this object target, string info)
{
_metadataTable.Add(target, new Metadata { Info = info });
}
public static string GetMetadata(this object target)
{
return _metadataTable.TryGetValue(target, out Metadata metadata) ? metadata.Info : null;
}
private class Metadata
{
public string Info { get; set; }
}
}
// 使用示例
var obj = new object();
obj.SetMetadata("附加信息");
Console.WriteLine(obj.GetMetadata()); // 输出:附加信息