Skip to main content

强引用与弱引用

面试题

  1. 什么是强引用和弱引用?

强引用是默认的对象引用方式,会阻止GC回收对象;弱引用则允许GC在需要时回收对象,不会阻止垃圾回收。

  1. 什么时候应该使用弱引用?

适合使用弱引用的场景包括:缓存系统、事件订阅、对象生命周期跟踪等需要引用对象但又不希望阻止其被回收的情况。

  1. 如何检查弱引用对象是否还存在?

可以通过WeakReference的IsAlive属性检查,或使用TryGetTarget方法尝试获取目标对象。

  1. 弱引用有什么性能影响?

弱引用有轻微的性能开销,因为每次访问都需要检查对象是否存活。因此高频访问的数据更适合强引用结合缓存过期策略。

  1. 什么是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()); // 输出:附加信息