【问题标题】:Static variable that will not be disposed不会被释放的静态变量
【发布时间】:2013-02-09 12:16:06
【问题描述】:

我的班级中有一个static StreamWriter 变量:

private static StreamWriter streamWriter = CreateStreamWriter(pathToFile);

我没有在我的应用中关闭这个 StreamWriter,因为它需要在应用运行时打开。

如果我多次启动和停止此应用程序,我会出现内存泄漏吗?还是在关闭应用程序时正确处理对象?

此类是 ASP.NET MVC 4 和 WPF 应用程序都使用的实用程序类。

感谢大家的回复。这是我添加的代码:

在包含 StreamWriter 的类中:

public static void OnApplicationExit(object sender, EventArgs e)
{
    try
    {
        streamWriter.Flush();
        streamWriter.Close();
        streamWriter.Dispose();
    }
    catch { }
}

public static void OnApplicationExit()
{
    try
    {
        streamWriter.Flush();
        streamWriter.Close();
        streamWriter.Dispose();
    }
    catch { }
}

在 ASP.NET MVC Global.Asax 中:

    protected void Application_End()
    {
        Utilities.MyClass.OnApplicationExit();
    }

【问题讨论】:

    标签: c# memory-management memory-leaks dispose resource-management


    【解决方案1】:

    使用using语句,这是最好的方式。

    使用 (var r = new StreamWriter(,,)) {

    }

    【讨论】:

    • 如何在静态变量上使用 using 语句?
    • 这是一个静态变量,在应用程序的整个生命周期中都需要存在。我不希望每次我需要使用它时都需要更新一个新的。
    • 在执行 I/O 时创建并处理它。好吧,只要你冲洗和关闭你可能不应该有任何问题,但使用确实是最好的方法。
    • 静态变量中的对象需要在应用程序运行时保持活动状态。我永远不会关闭它。问题是:系统会处理它吗?
    • 尝试 Application.ApplicationExit 事件。
    【解决方案2】:

    StreamWriter 不能保证在应用程序关闭时被释放。有时会,但在某些情况下这是不可能的。

    没有内存泄漏,因为它使用托管内存。当应用程序关闭时,整个堆被移除。

    这也不是资源泄漏,因为打开的文件句柄将在应用程序关闭时关闭。

    但是,StreamWriter 有一个缓冲区,如果它没有被释放,它就不会被刷新。这意味着您使用 writer 编写的最后内容可能会从文件中丢失。

    【讨论】:

    • 所以只要每次写完StreamWriter都flush一下,我的状态就很好了?
    • @user277498:是的,但是这样让资源挂起并不是一种好的做法。
    • 谢谢!我根据您的回答用我的实施更新了我的问题。如果您有任何其他想法,请告诉我。谢谢!
    【解决方案3】:

    当您说“多次启动和停止此应用程序”时,您的意思是进程退出并且每次都启动一个新进程吗?当一个进程退出时,它的所有内存都会被操作系统回收,所以实际上没有“内存泄漏”。

    话虽如此,我确实觉得在关机时清理资源是个好习惯;您可能决定确实要在同一进程中重新启动。修复泄漏比一开始就没有泄漏要困难得多。

    假设您必须在关闭时执行其他操作,例如刷新写入器。然后,您将需要某种在关机时启动的钩子。

    【讨论】:

      【解决方案4】:

      Streamwriter 实现 IDisposable。所以如果你不调用它的 Dispose 方法,你就不能保证你正确地处理了它的资源。

      在我看来,您有两个基本选择:

      1. 保留 StreamWriter 的静态实例,但在应用程序关闭时捕获,然后调用 Streamwriter.Dispose() 以释放资源。我不知道您的应用程序是 WPF 还是 Windows 窗体应用程序,但如果您可以找到在应用程序关闭时触发的事件,您可以在那里调用 dispose。我认为Application.ApplicationExit 可能是您需要的。

      2. 将 StreamWriter 转换为实例变量,使用 using 语句对其进行实例化,执行 IO,然后立即将其丢弃:

        using(var writer = new StreamWriter())
        {
            //do your IO here
        }
        

      编辑:您指出您的应用是 ASP.Net 应用。对于 ASP.Net 应用程序,您可以在 global.asax 的 Application_Start 事件中创建静态变量,并在 global.asax 的 Application_End 事件中释放静态变量。

      【讨论】:

      • 谢谢!这是一个 ASP.NET MVC 4 应用程序。
      【解决方案5】:

      如果我多次启动和停止此应用程序,我会出现内存泄漏吗?

      没有。当进程结束时,与进程相关的所有资源都会自动返回给操作系统。这是 Windows 的一个功能;所有进程都是如此,而不仅仅是托管代码进程。

      正如其他人所指出的,您可能会丢失数据,但不会泄漏内核对象

      关闭应用后对象是否被正确处理?

      不一定。如果应用程序因“快速失败”而终止,那么显然没有终结器运行,因为 nothing 运行。如果应用程序因未处理的异常而终止,则终结器是否运行由实现定义。

      此外,正如 Raymond Chen 曾经指出的那样,当您知道进程正在关闭时运行终结器就像在拆除建筑物之前扫地一样。这是浪费时间和精力。

      简而言之,您不应依赖运行终结器来确保程序的正确性。

      【讨论】:

        猜你喜欢
        • 2011-01-26
        • 1970-01-01
        • 1970-01-01
        • 2011-11-11
        • 2011-12-18
        • 1970-01-01
        • 2011-07-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多