c# - 为什么我的 C# 方法存在用户对象的内存泄漏?

标签 c# .net

我一直在研究从数据库中提取大量记录的数据导出程序。其中一个步骤涉及将 RTF 文本字符串转换为纯文本,这最终导致用户对象在运行时发生内存泄漏。任务管理器将显示的列之一是“USER objects”——当它达到 ~10,000 时,程序将用完分配空间,程序将出现“错误创建窗口句柄”错误

发生这种情况是因为我没有在方法结束时处理我的对象。

我的问题是,为什么 C#/.net 没有为我处理它?

这是一个可以重现泄漏的快速代码示例。将代码放入 Winforms 应用程序并按下按钮以使其循环遍历内存浪费。

private void wasteMemory()
{
    System.Windows.Forms.RichTextBox rtfBox = new System.Windows.Forms.RichTextBox();

    //RTF text that reads "Hello World"
    rtfBox.Rtf = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}}  {\\colortbl ;\\red0\\green0\\blue0;}  \\viewkind4\\uc1\\pard\\cf1\\fs29 Hello World} ";

    //If line below is commented out, User Objects grow out of control.
    //rtfBox.Dispose();
}

private void button1_Click(object sender, EventArgs e)
{
    for (int i = 1; i < 100000; i++)
    {            
        wasteMemory();
    }
}

据我了解,方法的范围内创建的任何对象都会在方法完成时被处理掉。我预计 rtfBox 会被处理掉,但它没有。

最佳答案

到目前为止,这里的每个答案都不完整。是的,确实必须清理非托管资源,但实现 IDisposable 的类已经这样做了。这不是重点。

在正确实现 IDisposable 的类中,如果未显式或隐式处置对象,则将在垃圾回收的终结器阶段处置该对象。但是,当对象超出范围时,此过程不会立即发生。 gc 运行可能需要几分钟甚至几小时。

这里的问题是,如果您自己不调用 Dispose()(或通过将其包装在 using 语句中隐式调用 Dispose()),那么(如果类正确实现了)该对象将不会被释放,直到垃圾收集器运行,这可能需要相当长的时间。

这意味着在垃圾收集器开始处理未引用的对象之前,您可能会用完非托管资源。而这正是您遇到的问题。

自己调用 Dispose() 可确保非托管对象在您处理完它们后立即被清理,而不是在 GC 处理它时。

把它想象成一个图书馆。有人借了一本书,书架上有 5 本。当其他人借阅该图书馆时,有些人会归还它们……但它们不会立即被放在书架上,它们会坐在归还箱中,直到有人抽出时间检查它们并重新上架。

调用 Dispose 就像将书交给图书管理员,让他们立即登记,然后将其放回书架,以便下一个人可以拿到。

关于c# - 为什么我的 C# 方法存在用户对象的内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18747309/

相关文章:

c# - "null this"是可以接受的扩展方法使用吗?

c# - 响应.Cookies : How to append with expiration?

javascript - 如何访问此网格的行对象?

c# - 如何在同一软件的不同版本之间共享设置

c# - 查找枚举成员

c# - 使用 HttpWebRequest 类

c# - 消息代理消费者/生产者在客户端出现故障时重新分配?

c# - 如何打印在运行时执行程序的当前代码?

c# - 结合应用程序域远程处理和任务时出现死锁

C# Excel RTD 服务器多实例断开一张纸上的所有公式停止另一张纸上的公式