繁体   English   中英

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

[英]Are C# weak references in fact soft?

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

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

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

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

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

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

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

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


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

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

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


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

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


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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM