mar*_*mnl 12 .net c# memory-leaks
例如,如果我有一个分层数据结构:
class Node
{
public List<Node> children;
}
Run Code Online (Sandbox Code Playgroud)
然后在其中一个父母那里填充到很多级别:
myNode.children.Clear();
Run Code Online (Sandbox Code Playgroud)
这将清除所有对直系孩子的提及 - 但那些直系孩子所引用的所有大孩子,大孙子等等呢?C#是否足够聪明,知道它们不再需要它们会被垃圾收集?
我已阅读使用WPF数据绑定而没有实现接口INotifyChanged可能导致内存泄漏:http://blogs.msdn.com/b/micmcd/archive/2008/03/07/avoiding-a-wpf-memory-leak-with-数据绑定-black-magic.aspx,在托管环境中如何实现?
Jon*_*eet 14
是的,垃圾收集器会发现孙子等是垃圾.基本上,如果没有办法到达某个对象,它就被认为是垃圾并且有资格收集.
至于如何记忆"泄露"是在托管代码中可能的-这是典型的,如果你结束了一个对象,它是通过对象引用到达的,但是那里没有办法,你可以最终通过API"清理"那些引用.
在你引用的博客文章中就是这种情况:
WPF检查是否存在实现INotifyProperyChanged的问题.如果存在对未实现此接口的数据绑定,则它在全局表中创建记录.该记录未被清除,因为WPF无法检查何时不再需要该DB记录.
因此,这个全局表维护引用,并且您无法指示可以清除表中的项.
C#并不关心.这是CLR完成GC的工作.
GC从已知的根对象(静态字段,局部变量,...)开始,并遍历引用,直到找到所有可到达的对象.可以收集所有其他对象(不包括一些终结器相关的东西).
因此,如果子引用实际上是对这些对象的唯一引用,那么也将收集大孩子.但是如果一些活着的外部对象仍然具有对您的一个节点的引用,则该节点和它引用的所有其他对象将保持活动状态.
托管内存泄漏是由保持对象存活的引用引起的.
例如,当使用数据库时,GUI具有对象的引用,使它们保持活动状态.
类似地,订阅事件会使与事件处理程序关联的对象保持活动状态.所以有时事件使用弱引用来避免这个问题.
垃圾收集器只收集不再使用的对象 - 内存泄漏是由仍然持有对象引用的对象引起的,即使它们不应该.
在你的情况下,如果一个大孩子被另一个对象使用,那么.Clear会将它从节点列表中删除,但垃圾收集器不会收集它.它会收集所有其他的大孩子.
例:
class Foo {
public Node SomeProperty {get; set;}
public void SomeFunction(){
var node = new Node { children = new List<Node>() };
var childNode = new Node();
var childNode2 = new Node();
node.children.Add(childNode);
node.children.Add(childNode2);
SomeProperty = childNode2;
node.children.Clear();
// childNode will be garbage collected
// childNode2 is still used by SomeProperty,
// so it won't be garbage collected until SomeProperty or the instance
// of Foo is no longer used.
}
}
Run Code Online (Sandbox Code Playgroud)