内存泄漏,不确定对象是否被管理

本文关键字:是否 管理 对象 不确定 泄漏 内存 | 更新日期: 2023-09-27 17:53:30

我遇到了c#内存泄漏的问题。我看到进程管理器中的内存使用增加了10-20mb(甚至更多),当不应该创建新对象时。

q1)我的印象是,托管对象将被GC自动删除。但是,当我使用dotTrace分析内存使用情况时,我编写的一个基本对象似乎有+10k个实例(在显示新/死的差异中)。我发现,如果这是c++,它会泄漏的地方,

public void TriggerEvent(string tEvent)
{
    oVariable tVar = GetVar(tEvent);
    if (tVar != null)
        sVariableParser.TriggerEvent(tVar);
    else
    {            
        tVar = new oVariable("@CXZ_TEMP_VAR", tEvent, 0, this);
        tVar._BlockDependancies = true;
        sVariableParser.TriggerEvent(tVar);
    }
}

其中oVariable定义为

class oVariable : IComparable 

似乎GC没有删除新的oVariables,我想知道我是否需要将oVariable实现为IDisposable并进行特定的系统调用以确保GC收集它?在oVariable中也有一些其他自定义对象,但我的印象是,不使用任何外部(没有COM对象等)的简单对象应该自动管理,或者我错了,我已经创建了非管理的数据结构?

q2)即使dotTrace Memory显示了很多新的oVariables,那里应该是零(也许GC是懒惰的),我仍然有一种感觉,内存泄漏可能来自windows窗体,特别是DataGridViews。我想知道是否有人可以告诉我,如果我需要做任何特定的内存释放函数调用后调用DGV更新/重绘使用

tGridView.Invoke(new UpdateGridViewCallBack(RedrawGlobalsViewGridView), tGridView);

我原以为new'd回调会自行清理。

内存泄漏,不确定对象是否被管理

首先,不要调用GC.Collect(),它会强制垃圾回收,但有一些讨厌的副作用。例如,它会将尚未准备好进行垃圾收集的所有内容向后推一代,并延迟其收集。MS有关于代等的信息

其次,GC只收集没有引用的对象。

假设你的sVariableParser是一个成员变量,它保存着对tVar的引用。当GC运行时,它会看到VariableParser依赖于tVar,而不会让它离开。

想象你有这样的东西:

public class House
{
   public Person Resident1 {get; set;}
}
public class Person
{
   public string Name {get; set;}
}

然后在你的代码中有

House.Resident1 = new Person {name = "John Calvin"};

当垃圾收集运行时,它不能清理绑定到Resident1的Person对象,直到House超出作用域并且不再使用。

也就是说,GC会清理你的引用,但我猜你有一些代码抓住了你的tVar,而你没有意识到这一点。

首先,GC不受任何人的直接控制,而是运行时的直接控制;它只会在运行时认为应该运行时运行。这意味着计划进行清理的对象可能会持续几秒钟甚至几分钟,直到内存条件表明应该执行清理。

然而,等待清理的10,000个死实例听起来像是内存泄漏。检查:

oVariable是否包含或引用一个非托管或可分配的对象?如果是这样,oVariable应该实现IDisposable并执行清理,释放对它不"拥有"的对象的引用,和/或处置它控制的对象。您可以使用一种模式来避免必须显式调用Dispose();看http://www.codeproject.com/KB/cs/idisposable.aspx

oVariable是否订阅其他对象的任何事件?只要具有事件的对象在内存中,任何将其处理程序添加到事件的oVariable都将保留在内存中,因为对该方法的引用将使对象保持"活动",就GC而言。同样,您应该创建一个IDisposable实现,并让对象从它侦听的任何事件中删除自身。

最后,我注意到在你对另一篇文章的评论中,你对其他oVariables保持了向上和向下的层次关系。只要oVariable在这些列表中,它就会被引用。我会反复检查所有从这些列表中添加和删除实例的代码;你忘记把东西移到某个地方,所以它们会无限期地留在那里。同样,处理oVariable应该包括(1)从任何/所有主oVariables中删除作为Slave的变量引用,(2)从任何/所有Slave中删除作为Master的变量引用,最后(3)清除变量的Master和Slave列表。只有当对象在内存中完全"孤立"时,GC才会销毁它。

oVariable的内部实现是什么样子的?如果你正在使用继承IDisposable的任何资产,你需要关闭它们(或使用using块),以确保它们被正确处置。