当前位置:  开发笔记 > 编程语言 > 正文

如何在.net中部署一个类?

如何解决《如何在.net中部署一个类?》经验,为你挑选了5个好方法。

.NET垃圾收集器最终将释放内存,但如果你想立即恢复内存呢?你需要在课堂MyClass上使用什么代码来调用

MyClass.Dispose()

并通过变量和对象释放所有已用空间MyClass



1> Curt Hagenlo..:

IDisposable与释放内存无关.IDisposable是一种用于释放非托管资源的模式- 内存绝对是一种托管资源.

指向GC.Collect()的链接是正确的答案,但Microsoft .NET文档通常不鼓励使用此函数.

编辑:为这个答案赢得了大量的业力,我觉得有责任详细说明,以免.NET资源管理的新人得到错误的印象.

在.NET进程中,有两种资源 - 托管和非托管."托管"意味着运行时控​​制资源,而"非托管"意味着它是程序员的责任.实际上,我们今天在.NET中只关注一种托管资源 - 内存.程序员告诉运行时分配内存,然后由运行时决定内存何时可以释放..NET用于此目的的机制称为垃圾收集,您只需使用Google即可在互联网上找到有关GC的大量信息.

对于其他类型的资源,.NET对清理它们一无所知,因此必须依赖程序员来做正确的事情.为此,该平台为程序员提供了三个工具:

    IDisposable接口和VB和C#中的"using"语句

    终结

    由许多BCL类实现的IDisposable模式

第一个允许程序员有效地获取资源,使用它然后在同一方法中释放所有资源.

using (DisposableObject tmp = DisposableObject.AcquireResource()) {
    // Do something with tmp
}
// At this point, tmp.Dispose() will automatically have been called
// BUT, tmp may still a perfectly valid object that still takes up memory

如果"AcquireResource"是一个工厂方法(例如)打开文件并且"Dispose"自动关闭文件,则此代码不会泄漏文件资源.但是"tmp"对象本身的内存仍然可以分配.那是因为IDisposable接口绝对没有与垃圾收集器的连接.如果您确实想要确保释放内存,那么您唯一的选择就是调用GC.Collect()强制垃圾回收.

但是,不能强调这可能不是一个好主意.让垃圾收集器完成它的设计目的,即管理内存通常要好得多.

如果资源使用的时间较长,会使其生命周期跨越多种方法,会发生什么?显然,"using"语句不再适用,因此程序员必须在完成资源时手动调用"Dispose".如果程序员忘记会发生什么?如果没有回退,那么进程或计算机最终可能会耗尽任何未正确释放的资源.

这就是终结器的用武之地.终结器是你的类上与垃圾收集器有特殊关系的方法.GC承诺 - 在为任何类型的对象释放内存之前 - 它将首先给终结器一个机会进行某种清理.

因此,对于文件,理论上我们根本不需要手动关闭文件.我们可以等到垃圾收集器到达它然后让终结器完成工作.不幸的是,这在实践中效果不好,因为垃圾收集器运行不确定.该文件可能会比程序员期望的更长时间保持打开状态.如果有足够的文件保持打开状态,则在尝试打开其他文件时系统可能会失败.

对于大多数资源,我们都需要这两样东西.我们希望一个约定能够说"我们现在已经完成了这个资源",并且我们希望确保如果我们忘记手动执行清理,则至少有一些机会自动进行清理.这就是"IDisposable"模式发挥作用的地方.这是一个允许IDispose和终结器很好地一起玩的约定.您可以通过查看IDisposable的官方文档来了解该模式的工作原理.

结论:如果您真正想要做的就是确保释放内存,那么IDisposable和终结器将无法帮助您.但IDisposable接口是所有.NET程序员都应该理解的极其重要的模式的一部分.



2> Patrik Svens..:

您只能处置实现IDisposable接口的实例.

强制垃圾收集立即释放(非托管)内存:

GC.Collect();  
GC.WaitForPendingFinalizers();

这通常是不好的做法,但是在.NET框架的x64版本中存在一个错误,它使GC在某些情况下表现得很奇怪,然后你可能想要这样做.我不知道这个bug是否已经解决了.有人知道吗?

要处理一个类,你可以这样做:

instance.Dispose();

或者像这样:

using(MyClass instance = new MyClass())
{
    // Your cool code.
}

这将在编译时转换为:

MyClass instance = null;    

try
{
    instance = new MyClass();        
    // Your cool code.
}
finally
{
    if(instance != null)
        instance.Dispose();
}

您可以像这样实现IDisposable接口:

public class MyClass : IDisposable
{
    private bool disposed;

    /// 
    /// Construction
    /// 
    public MyClass()
    {
    }

    /// 
    /// Destructor
    /// 
    ~MyClass()
    {
        this.Dispose(false);
    }

    /// 
    /// The dispose method that implements IDisposable.
    /// 
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// 
    /// The virtual dispose method that allows
    /// classes inherithed from this one to dispose their resources.
    /// 
    /// 
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources here.
            }

            // Dispose unmanaged resources here.
        }

        disposed = true;
    }
}



3> Keith..:

对这个问题的回答有点困惑.

标题询问有关处置,但后来说他们想要立即回忆.

.Net是管理的,这意味着当您编写.Net应用程序时,您不需要直接担心内存,但成本是您无法直接控制内存.

.Net决定什么时候最好清理和释放内存,而不是你作为.Net编码器.

Dispose是一种告诉.Net的方法,你已经完成了某些事情,但它实际上不会释放内存,直到这是最好的时间.

基本上.Net实际上会收集内存,因为它最容易收集内存 - 它非常擅长决定何时.除非你正在写一些非常耗费内存的东西,否则你通常不需要推翻它(这也是游戏通常不是用.Net编写的部分原因 - 它们需要完全控制)

在.Net中,您可以GC.Collect()立即强制使用它,但这几乎总是不好的做法.如果.Net尚未清理它,那意味着它不是一个特别好的时机.

GC.Collect()选择.Net识别的对象.如果您还没有处理需要它的对象.Net可能会决定保留该对象.这意味着GC.Collect()只有正确实施一次性实例才有效.

GC.Collect()不是对正确使用IDisposable的一个替代品.

因此Dispose和内存没有直接关系,但它们并不需要.正确处理将使您的.Net应用程序更高效,因此使用更少的内存.


在.Net中99%的时间是以下最佳做法:

规则1:如果你不处理任何非托管或实现的东西,IDisposable 那么不要担心Dispose.

规则2:如果你有一个实现IDisposable的局部变量,请确保你在当前范围内删除它:

//using is best practice
using( SqlConnection con = new SqlConnection("my con str" ) )
{
    //do stuff
} 

//this is what 'using' actually compiles to:
SqlConnection con = new SqlConnection("my con str" ) ;
try
{
    //do stuff
}
finally
{
    con.Dispose();
}

规则3:如果一个类有一个实现IDisposable的属性或成员变量,那么该类也应该实现IDisposable.在该类的Dispose方法中,您还可以处理您的IDisposable属性:

//rather basic example
public sealed MyClass :
   IDisposable
{   
    //this connection is disposable
    public SqlConnection MyConnection { get; set; }

    //make sure this gets rid of it too
    public Dispose() 
    {
        //if we still have a connection dispose it
        if( MyConnection != null )
            MyConnection.Dispose();

        //note that the connection might have already been disposed
        //always write disposals so that they can be called again
    }
}

这并不是很完整,这就是为什么这个例子是密封的.继承类可能需要遵守下一个规则......

规则4:如果类使用非托管资源,则实现IDispose 添加终结器.

.Net无法对非托管资源做任何事情,所以现在我们谈论的是内存.如果你不清理它可能会导致内存泄漏.

Dispose方法需要处理托管非托管资源.

终结者是一个安全捕获 - 它确保如果其他人创建和您的类的实例并且未能处置它,那么"危险的" 非托管资源仍然可以被.Net清理.

~MyClass()
{
    //calls a protected method 
    //the false tells this method
    //not to bother with managed
    //resources
    this.Dispose(false);
}

public void Dispose()
{
    //calls the same method
    //passed true to tell it to
    //clean up managed and unmanaged 
    this.Dispose(true);

    //as dispose has been correctly
    //called we don't need the 

    //'backup' finaliser
    GC.SuppressFinalize(this);
}

最后这个带有布尔标志的Dispose重载:

protected virtual void Dispose(bool disposing)
{
    //check this hasn't been called already
    //remember that Dispose can be called again
    if (!disposed)
    {
        //this is passed true in the regular Dispose
        if (disposing)
        {
            // Dispose managed resources here.
        }

        //both regular Dispose and the finaliser
        //will hit this code
        // Dispose unmanaged resources here.
    }

    disposed = true;
}

请注意,一旦完成所有其他托管代码创建类的实例,就可以像对待任何其他IDisposable一样对待它(规则2和3).



4> Brian Lyttle..:

是否也适当提一下,处置并不总是指内存?我比文件更频繁地处理资源这样的文件引用.GC.Collect()直接与CLR垃圾收集器相关,可能会也可能不会释放内存(在任务管理器中).它可能会以负面方式影响您的应用程序(例如性能).

在一天结束时,你为什么要立即回忆?如果来自其他地方存在内存压力,操作系统将在大多数情况下为您提供内存.



5> Scott Dorman..:

看看这篇文章

实现Dispose模式,IDisposable和/或终结器与内存被回收时完全无关; 相反,它与告诉GC 如何回收内存有关.当您调用Dispose()时,您无法与GC进行交互.

只有在确定需要(称为内存压力)然后(并且只有那时)才会为未使用的对象释放内存并压缩内存空间时,GC才会运行.

可以调用GC.Collect(),但你真的不应该,除非有非常充分的理由(这几乎总是"从不").当您强制执行这样的带外收集周期时,实际上会导致GC执行更多工作,最终可能会损害您的应用程序性能.在GC收集周期的持续时间内,您的应用程序实际上处于冻结状态...运行的GC周期越多,应用程序冻结的时间就越长.

也有一些本地的Win32 API调用,你可以对你的自由工作集,但即使是那些应该避免,除非有非常充分的理由这样做.

Gargbage收集运行时背后的整个前提是,您不必担心运行时分配/释放实际内存的时间(尽可能多); 你只需要担心确保你的对象在被问到后知道如何清理它.

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有