Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# GC会释放已用内存吗_C#_.net - Fatal编程技术网

C# GC会释放已用内存吗

C# GC会释放已用内存吗,c#,.net,C#,.net,我有一个引用子对象的父对象,另外父对象还有一个侦听子对象事件的事件处理程序 如果对父对象的所有引用都将被释放,那么通过父对象和子对象使用的内存是否会通过GC释放?(假设不再存在对子对象和父对象的引用) 请注意,我知道GC不会立即做出反应。我的问题不是释放父对象后是否立即释放内存。我的问题是,如果内存被释放了 更新 对我来说,答案似乎是明确的是的,GC能够解析这个循环引用。 但对于所有读过这篇文章并有类似问题的人,请注意不要让活动注册处于开放状态。这只是一个注册没有问题的特殊例子。在其他情况下,事

我有一个引用子对象的父对象,另外父对象还有一个侦听子对象事件的事件处理程序

如果对父对象的所有引用都将被释放,那么通过父对象和子对象使用的内存是否会通过GC释放?(假设不再存在对子对象和父对象的引用)

请注意,我知道GC不会立即做出反应。我的问题不是释放父对象后是否立即释放内存。我的问题是,如果内存被释放了

更新

对我来说,答案似乎是明确的是的,GC能够解析这个循环引用。 但对于所有读过这篇文章并有类似问题的人,请注意不要让活动注册处于开放状态。这只是一个注册没有问题的特殊例子。在其他情况下,事件注册可能会导致严重的内存泄漏

vilx提供了一个很好的资源,涵盖了这个问题:
是的。NET GC处理循环引用没有问题(假设您没有使用非托管资源,或者如果使用了,则实现IDisposable)。

好吧,如果没有其他任何东西使用相同的
\u childClass
实例,那么它将被收集。但是,我不确定您不分离事件处理程序的含义是什么-未注册的事件处理程序是.NET应用程序中无法GC的内存泄漏的一个来源-您对这个问题的看法很有趣

更新:证明我对内存泄漏源的理解是错误的。如果类A订阅了类B但没有取消订阅,那么只有在收集B时才会收集A(因为B的订阅列表保持A活动)。对于长寿命事件源,这可能是订阅者的问题

问题发生在所有对象的生命周期中,但实际上,如果B和A一样短暂,则泄漏不会被注意到,通常也不会成为问题


更新2:在OP示例中,子对象是源,父对象是订阅者-GC可以处理这种情况-只要子对象不在父对象之外引用,这意味着子对象不可省略以进行收集(这将使父对象保持活动状态)。这些引用在何处或如何定义并不重要;GC会对其进行跟踪并进行相应处理

然而,值得注意的是:GC本质上是非常不确定的(首先,它在一个单独的线程上运行),并且可能在一段时间内不会破坏内存中的对象。“一段时间”通常几乎是瞬时的,除非在处理器太忙和/或大量内存被立即释放的特殊情况下

childClass.SomeEvent += ChildClass_SomeEvent; childClass.SomeEvent+=childClass\u SomeEvent; 此代码表示该子级引用了父级。这是循环引用,GC可以处理。在另一种情况下,取消订阅的活动可能是危险的。假设您没有使用childClass,而是使用了一些独立实例:

anotherClass.SomeEvent += AnotherClass_SomeEvent; anotherClass.SomeEvent+=anotherClass\u SomeEvent;
现在,当您认为可以收集ParentClass时,如果另一个类仍然存在并且事件订阅没有取消,它实际上仍然是活动的。只有在收集另一个类时,才能收集ParentClass。

IMHO事件处理程序和委托通常与任何其他引用没有区别。因此,不需要显式分离。事件处理程序是臭名昭著的“内存泄漏”源,因为人们往往会忘记它们,但仅此而已。如果将事件从类A注册到类B,然后收集A,则无法收集B,因为类A注册的事件处理程序引用无效-这就是.NET中的泄漏源。如果A在收集之前在终结器中或以其他方式删除订阅,那么B也可以正常收集。Uups,如果我理解正确的话,循环引用没有解决?你搞错了。“订阅列表”与任何其他集合(例如,您的标准ArrayList)没有什么不同,它是拥有该事件的类的成员。因此,如果对该类的所有引用都丢失,那么对订阅列表的引用也会丢失,并且这两个对象会一起收集。另外,谷歌搜索你的关键词给了我这个,完全支持我上面所说的:有一个常见的漏洞,但它是这样的模式:
a.e+=B.m;B=零;GC.Collect()B
。这是一个典型的场景,很容易错过。我也有过类似的虫子(找到它很“有趣”…),但反过来它不起作用,这是一个由不了解这一切的人传播的神话。正如Joralsav Jandek所写,GC知道循环引用,并且不将子项计算为引用计数?在您提供的示例中,我看到没有循环引用。。。即使有,GC也不需要专门处理循环引用,我知道。每个对象的引用计数就足够了。父对象引用子对象,并且在子对象的事件列表中是对父对象的引用,以通知它有关某个事件。在我看来是循环的。我错了吗?哦,对不起,我忽略了事件处理程序的定义位置。所以在这方面它是循环的,尽管它并没有像我所说的那样真正产生影响。请看我对Adam帖子的评论。循环引用是基于引用计数的GC的一个问题。例如,VB6使用基于计数的GC,如果要防止内存泄漏,必须清除循环引用。Python对循环引用有特殊的处理。这与.NET的GC无关,thoug anotherClass.SomeEvent += AnotherClass_SomeEvent;