C# 弱引用实际上是软的吗?
不。
我错了吗?
你错了。弱引用的目的绝对不是您所说的缓存。这是一个普遍的误解。
他们能够延长生命周期,还是表现得像真正的弱裁判?
不,它们不会延长使用寿命。
考虑以下程序(F# 代码):
do
let x = System.WeakReference(Array.create 0 0)
for i=1 to 10000000 do
ignore(Array.create 0 0)
if x.IsAlive then "alive" else "dead"
|> printfn "Weak reference is %s"
此堆分配一个空数组,该数组可立即进行垃圾回收。然后我们循环 10M 次分配更多无法访问的数组。请注意,这根本不会增加内存压力,因此没有动机收集弱引用引用的数组。然而程序会打印“Weak reference is dead”,因为它仍然被收集了。这是弱引用的行为。软引用会一直保留到实际需要它的内存为止。
这是另一个测试程序(F# 代码):
open System
let isAlive (x: WeakReference) = x.IsAlive
do
let mutable xs = []
while true do
xs <- WeakReference(Array.create 0 0)::List.filter isAlive xs
printfn "%d" xs.Length
这会不断过滤掉无效的弱引用,并在链表的前面添加一个新的引用,每次都打印出链表的长度。在我的机器上,这永远不会超过 1,000 个幸存的弱引用。它在循环中上升然后下降到零,大概是因为所有弱引用都在每个 gen0 集合中收集。同样,这是弱引用而不是软引用的行为。
请注意,这种行为(在 gen0 集合中积极收集弱引用对象)正是使弱引用成为缓存的错误选择的原因。如果您尝试在缓存中使用弱引用,那么您会发现缓存被无缘无故地刷新了很多。