C#弱引用实际上是软的吗?

时间:2011-10-13 14:46:24

标签: c# .net garbage-collection weak-references soft-references

基本的不同之处在于,应该在每次运行GC时声明弱引用(保持内存占用率低),而软引用应该保留在内存中,直到GC实际需要内存(它们尝试扩展生命周期但可能随时失败,这对于例如特别是相当昂贵的对象的缓存很有用)。

据我所知,没有明确说明弱引用如何影响.NET中对象的生命周期。如果它们是真正的弱参考,它们根本不应该影响它,但是这也会使它们对于我们认为缓存的主要目的而言毫无用处(我错了吗?)。另一方面,如果他们的行为像软参考,他们的名字有点误导。

就我个人而言,我认为它们的行为类似于软参考,但这只是一种印象,而不是创立。

当然,实施细节也适用。我问的是与.NET的弱引用相关的心态 - 它们是否能够延长寿命,还是它们的行为像真正的弱引用?

(尽管有许多相关问题我还没找到这个具体问题的答案。)

3 个答案:

答案 0 :(得分:13)

  

C#弱引用实际上是否软?

没有

  我在那里错了吗?

你错了。弱引用的目的绝对是 not 缓存,就像你的意思。这是一种常见的误解。

  

他们能够延长寿命,还是表现得像真正的弱参考?

不,他们不会延长寿命。

考虑以下程序(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次分配更多无法访问的数组。请注意,这根本不会增加内存压力,因此没有动机收集弱引用所引用的数组。然而,程序打印出“弱引用已死”,因为它仍然被收集。这是弱引用的行为。软件引用将被保留,直到实际需要它为止。

这是另一个测试程序(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集合中积极收集弱引用的对象)正是弱引用对于缓存的错误选择。如果您尝试在缓存中使用弱引用,那么您将发现您的缓存无缘无故地被刷新了。

答案 1 :(得分:8)

我没有看到任何信息表明他们会增加他们指向的对象的生命周期。我读到的关于GC用来确定可达性的算法的文章也没有以这种方式提及它们。所以我希望它们对对象的生命周期没有影响。

  


  此句柄类型用于跟踪对象,但允许收集它。收集对象时,GCHandle的内容将归零。在终结器运行之前,弱引用被归零,因此即使终结器恢复对象,弱引用仍然归零。

     

WeakTrackResurrection
  此句柄类型与Weak类似,但如果在完成期间对象复活,则句柄不会归零。

http://msdn.microsoft.com/en-us/library/83y4ak54.aspx


有一些机制可以使一个无法访问的对象在垃圾收集中存活下来。

  • 对象的生成大于发生的GC的生成。这对于大对象特别有意义,大对象在大对象堆上分配,并且为此目的始终被视为Gen2。
  • 具有终结器的对象以及可从中获取的所有对象在GC中存活。
  • 可能有一种机制,旧的对象的前引用可以保持年轻的对象存活,但我不确定。

答案 2 :(得分:-1)


弱引用不会延长对象的生命周期,因此一旦所有强引用都超出范围,就允许对其进行垃圾回收。它们可用于保留初始化成本昂贵的大型对象,但如果它们没有被主动使用,则应该可用于garabage收集。