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

发布于 2024-11-04 03:19:27 字数 1077 浏览 1 评论 0原文

我在 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);

我假设新的 d 回调会自行清理。

I'm having trouble with a memory leak in C#. I'm seeing the memory usage in process manager increasing 10-20mb (and more) when no new objects should be getting created.

q1) I am under the impression that managed objects will automatically be deleted by the GC. But when I profile the memory usage using dotTrace, there seems to be +10k instances (in the show new / dead differences) of a basic object I wrote. I found the place that it would be leaking if this were 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);
    }
}

Where oVariable is defined as

class oVariable : IComparable 

It seems that the GC is not deleting the new'd oVariables, I am wondering do I need to implement oVariable as IDisposable and make a specific system call to make sure the GC collects it? There are also a few other custom objects within oVariable, but I was under the impression that simple objects which don't use anything external (no COM objects etc) should automatically be managed, or am I mistaken and I've been created unmanaged data structures?

q2) Even with dotTrace Memory showing a lot of new oVariables where there should be zero (maybe the GC is lazy), I still have a feeling the memory leak could be coming from the windows forms, specifically DataGridViews. I was wondering if someone could tell me if I need to do any specific memory deallocation function calls after invoking a DGV update/redraw using

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

I had assumed the new'd call back would clean up after itself.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

以往的大感动 2024-11-11 03:19:27

首先,不要调用 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,而你没有意识到这一点。

First, do not call GC.Collect() it will force garbage collection, but has some nasty side effects. For example, it will push everything that is not ready for garbage collection back a generation and delay it's collection. MS has information about generations etc

Secondly, GC will only collect objects if there are no references to it.

So let's say your sVariableParser is a member variable that holds a reference to your tVar. When the GC runs, it's going to see that VariableParser is depending on tVar and not let it go.

Imagine that you have something like this:

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

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

Then in your code you have

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

When garbage collection runs, it can't clean up the Person object that is tied to Resident1 until House falls out of scope and is no longer used.

So all that is to say, that GC will clean up your references, but I'm guessing you've got some code holding on to your tVar, and you don't realize it.

淤浪 2024-11-11 03:19:27

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

然而,10,000 个等待清理的死亡实例听起来像是内存泄漏。需要检查的一些事项:

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

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

最后,我在您对另一篇文章的评论中注意到,您与其他 oVariables 保持向上和向下的层次关系。只要 oVariable 位于任何这些列表中,它就会被引用。我会仔细检查所有从这些列表中添加和删除实例的代码;您忘记在某处删除对象,因此它们会无限期地徘徊。同样,处置 oVariable 应涉及 (1) 从任何/所有主 oVariable 中删除作为从属变量的任何引用,(2) 从任何/所有从属中删除作为主变量对变量的任何引用,最后 ( 3) 清除变量的Master和Slave列表。只有当对象在内存中完全“孤立”时,GC 才会销毁它。

First off, the GC isn't under anyone's direct control but the runtime's; it will run only when the runtime thinks it should. That means that objects scheduled for cleanup may persist for seconds or even minutes until the memory conditions indicate a cleanup should be performed.

However, 10,000 dead instances waiting to be cleaned up sounds like a memory leak. Some things to check:

Does oVariable contain or reference an unmanaged or IDisposable object? If so, oVariable should implement IDisposable and perform cleanup, releasing references to objects it does not "own", and/or disposing of objects it does control. There is a pattern you can use to avoid having to call Dispose() explicitly; look at http://www.codeproject.com/KB/cs/idisposable.aspx.

Does oVariable subscribe to any events of other objects? As long as the object with the event is in memory, any oVariable that has added its handler to the event will remain in memory, because the reference to the method will keep the object "alive" as far as GC is concerned. Again, you should create an IDisposable implementation and have the object remove itself from any events it listens to.

Lastly, I noticed in your comment to another post that you maintain hierarchical relationships, both upwards and downwards, to other oVariables. As long as an oVariable is in any of those lists, it's referenced. I would triple-check all code that adds and removes instances from these lists; you're forgetting to remove objects somewhere, so they hang around indefinitely. Again, disposing of an oVariable should involve (1) removing any reference to the variable as a Slave from any/all Master oVariables, (2) removing any reference to the variable as a Master from any/all of the Slaves, and finally (3) clearing the variable's Master and Slave lists. Only once the object is completely "orphaned" in memory will GC destroy it.

乖不如嘢 2024-11-11 03:19:27

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

What does the internal implementation of oVariable look like? If you're using any assets that inherit IDisposable, you'll need to close them (or use a using block) to make sure they're properly disposed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文