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

maf*_*afu 18 .net c# garbage-collection weak-references soft-references

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

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

就个人而言,我想他们的行为就像软参考,但这只是一种印象,而不是创立.

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

(尽管有一些相关的问题我还没找到这个具体问题的答案.)

Jon*_*rop 13

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"
Run Code Online (Sandbox Code Playgroud)

此堆分配一个空数组,该数组立即符合垃圾回收的条件.然后我们循环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
Run Code Online (Sandbox Code Playgroud)

这样可以过滤掉无效的弱引用,并将新的引用添加到链表的前面,每次打印出列表的长度.在我的机器上,这永远不会超过1,000个幸存的弱引用.它会逐渐上升然后在周期内降至零,大概是因为所有的弱引用都是在每个gen0集合中收集的.同样,这是弱引用的行为,而不是软引用.

请注意,这种行为(gen0集合中弱引用对象的积极集合)正是使弱引用成为缓存的错误选择的原因.如果您尝试在缓存中使用弱引用,那么您将发现您的缓存无缘无故地被刷新了很多.

  • 我不确定我能效法.我没有说弱的refs应该用于缓存,但软refs应该(我认为你说的是​​相同的).MSDN声明"C#weak refs"可用于缓存.所以,C#弱refs应该被称为"软",如果他们这样做,事实上,就像软refs一样. (2认同)

Cod*_*aos 8

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


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

WeakTrackResurrection
此句柄类型类似于弱,但如果对象在终结过程中复活的手柄不会归零.

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


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

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