Rau*_*otz 14 .net c# caching garbage-collection weak-references
我有一个缓存,使用WeakReferences缓存对象,以便在内存压力的情况下自动从缓存中删除它们.我的问题是缓存的对象在存储在缓存中后很快就会被收集.缓存在64位应用程序中运行,尽管仍然有超过4gig的内存可用,但所有缓存的对象都被收集(它们通常在那时存储在G2堆中).过程资源管理器显示没有手动引发的垃圾收集.
我可以采用哪些方法让对象更长寿?
jri*_*sta 15
使用WeakReferences作为引用缓存对象的主要方法并不是一个好主意,因为正如Josh所说,您将面临WeakReference和GC的任何未来行为变化的摆布.
但是,如果您的缓存需要任何类型的复活功能,则对待处理清除的项目使用WeakReferences非常有用.当项目符合驱逐标准,而不是立即驱逐它时,您将其引用更改为弱引用.如果有什么东西在GC之前请求它,你恢复它的强引用,并且对象可以再次生存.我发现这对于一些难以预测命中率模式的缓存很有用,并且频繁的"复活"是有益的.
如果你有可预测的命中率模式,那么我会放弃WeakReference选项并执行明确的驱逐.
在.net中,WeakReference根本不被视为GC立场的引用,因此任何仅具有弱引用的对象将在下一次GC运行中收集(用于适当的生成).
这使得弱引用完全不适合缓存 - 正如您的经验所示.
您需要一个"真正的"缓存组件,而缓存最重要的一点是获取一个驱逐策略(即关于何时从缓存中删除对象的规则)与您的应用程序的使用模式的良好匹配.
有一种情况是WeakReference基于缓存的缓存可能是好的:当类中项的有用性基于对它的引用的存在时.在这种情况下,弱的实习缓存可能是有用的.例如,如果有一个应用程序将反序列化许多大型不可变对象,其中许多预期是重复的,并且必须在它们之间进行许多比较.if X和Y是对某些不可变类类型的引用,测试X.Equals(Y)如果两个变量都指向同一个实例,那么会非常快,但如果它们指向恰好相同的不同实例,则可能会非常慢.如果反序列化对象碰巧匹配已存在引用的另一个对象,则从字典中获取对后一个对象的引用(需要一个慢速比较)可以加快将来的比较.另一方面,如果它匹配字典中的项目但字典是对该项目的唯一引用,则使用字典对象而不是简单地保持读入的对象几乎没有优势; 可能没有足够的优势来证明比较的成本.对于实习缓存,有WeakReferences 一旦对象不存在其他引用就会尽快失效,这将是一件好事.
不,WeakReference 对此并不好,因为垃圾收集器的行为可以并且将会随着时间的推移而改变,并且您的缓存不应该依赖于当前的行为。此外,许多您无法控制的因素也可能会影响内存压力。
.NET 的缓存有多种实现。您可以在 CodePlex 上找到大约十几个。我想您需要添加的是查看应用程序当前工作集的内容,以将其用作清除的触发器。
关于为什么您的物品被如此频繁地收集的另一说明。GC 在清理 Gen0 对象时非常积极。如果您的对象的生命周期非常短(直到对它的唯一引用是弱引用),那么 GC 就会通过尽快清理来完成其设计目的。