在C#中是否有非托管资源?

在C#中是否有非托管资源?,c#,garbage-collection,dispose,unmanagedresources,C#,Garbage Collection,Dispose,Unmanagedresources,我和朋友讨论了c#中的托管和非托管资源 据我的朋友说: 1.a)C#中的每个对象都是托管的,当我们在C#中编码时,没有什么比非托管对象或资源更好的了。非托管资源概念仅由C++来实现。 < 1)。我们在C++中是否有托管或非托管资源,我们需要明确地释放它。因为我们在C#中有自动垃圾收集器,所以我们不需要考虑管理资源 据我说: 2.a)如果我们没有非托管资源,那么为什么我们需要C#中的终结器或Dispose方法 2.b)垃圾收集器只包含有关已分配内存的信息,而不包含有关资源状态的信息。因此,我们需要

我和朋友讨论了c#中的托管和非托管资源

据我的朋友说:

1.a)C#中的每个对象都是托管的,当我们在C#中编码时,没有什么比非托管对象或资源更好的了。非托管资源概念仅由C++来实现。 < 1)。我们在C++中是否有托管或非托管资源,我们需要明确地释放它。因为我们在C#中有自动垃圾收集器,所以我们不需要考虑管理资源

据我说:

2.a)如果我们没有非托管资源,那么为什么我们需要C#中的终结器或Dispose方法

2.b)垃圾收集器只包含有关已分配内存的信息,而不包含有关资源状态的信息。因此,我们需要使用dispose方法来释放C#中的资源

我需要帮助理解上面哪些参数是正确的,以及关于c#中非托管资源的信息,无论它们是否存在


提前感谢。

在.NET中创建的对象是托管代码,但您的对象可以包含对非托管资源的引用。垃圾收集器(GC)确保在不再需要托管堆上分配的任何内存后将其清除。 然而,尽管垃圾收集器在确保内存不泄漏方面非常出色,但它不知道需要释放的其他资源。例如,垃圾收集器不知道如何关闭文件句柄,也不知道如何使用诸如CoAllocTaskMem之类的API释放托管堆外部分配的内存

管理这些类型资源的对象必须确保在不再需要它们时释放它们。可以通过重写Stural.Objor的终结方法来实现这一点,它允许垃圾回收器知道对象希望参与它自己的清理(在C++中,您使用C++析构函数语法,~MyObjor,而不是直接重写方法)。如果一个类有一个终结器,那么在收集该类型的对象之前,垃圾收集器将调用该对象的终结器,并允许它清理它可能持有的任何资源

该系统的一个问题是,垃圾收集器不能确定地运行,因此,在对对象的最后一次引用消失后,对象可能在很长一段时间内无法最终确定。如果您的对象持有昂贵或稀有的资源,例如数据库连接,则这可能是不可接受的。例如,如果您的对象只有10个可用连接中的1个打开,那么它应该尽快释放该连接,而不是等待垃圾收集器调用finalize方法


为此,您应该实现一个IDisposable接口。阅读更多信息。

在.net Framework下创建的每一件东西都是管理代码,因此内存仅由使用.net Framework manager创建的对象按框架使用

在.net框架之外创建的所有内容都是非托管代码。

当您想要释放hevy对象(如需要关闭文件或正在使用图形)并且想要释放与其相关的内存时,可以使用finalizer或dispose。您可以使用此方法。

确实,在CLR中创建的所有对象都由CLR管理,因此您无需关心它们


但是,当您开始使用CLR外部的资源(例如COM对象或设备上的锁)时,您有责任释放这些资源。CLR无法为您执行此操作,但提供了
IDisposable
接口,允许您编写执行清理的代码。

我们必须在.NET中处理非托管资源。一个很好的例子是与数据库的连接

我们必须显式关闭该非托管资源。这就是为什么我们在C#中有
Dispose

a)C#中的每个对象都是托管的,当我们在C#中编码时,没有什么比非托管的对象或资源更好的了。非托管资源概念仅来自C++。< /强>

这是不正确的。正如其他人所提到的,我们可以从C#(例如COM)之外获得非托管资源

但是,在C#中使用“非托管资源”而不访问非托管代码当然是可能的。这些资源可能不是严格意义上的垃圾收集的非托管资源,但作为开发人员,您必须处理清理这些资源。以线程为例:

class Foo
{
    private Thread thread = new Thread(new ThreadStart(DoLotsOfWork));
    private AutoResetEvent endThread = new AutoResetEvent(false);
    private int sum = 0;

    public Foo()
    {
        thread.Start();
    }

    public StopThread()
    {
        endThread.Set();
    }

    private void DoLotsOfWork()
    {
        while (!endThread.WaitOne(1000))
        {
            sum += 1;
        }
    }
}

static void Main(string[] args)
{
    Foo foo = new Foo();
    // Additional code...
    foo.StopThread();
}
假设附加代码返回或抛出异常。如果不显式调用StopThread,执行DoLotsOfWork的线程将不会结束,并且您的进程可能不会退出

<强> B)C++中是否有托管或非托管资源,我们需要显式地释放它。由于C语言中有自动垃圾收集器,我们不需要考虑管理资源。

>绝对> <强>必须< /强>考虑C语言中的资源管理。正如您所建议的,这就是IDisposable存在的原因

考虑对上述代码的修改:

class Foo : IDisposable
{
    private bool disposed = false;
    private Thread thread = new Thread(new ThreadStart(DoLotsOfWork));
    private AutoResetEvent endThread = new AutoResetEvent(false);
    private int sum = 0;

    public Foo()
    {
        thread.Start();
    }

    public StopThread()
    {
        endThread.Set();
    }

    public Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void DoLotsOfWork()
    {
        while (!endThread.WaitOne(1000))
        {
            sum += 1;
        }
    }

    private void Dispose(bool disposing)
    {
        if (!disposed && disposing)
        {
            StopThread();
            disposed = true;
        }
    }
}

static void Main(string[] args)
{
    using (Foo foo = new Foo())
    {
        // Additional code...
    }
}

现在我们可以确定,无论附加代码做什么,Foo类创建的线程都将在进程退出之前停止。

不,如果不使用非托管资源,就不可能编写C#程序。不可避免的是,C程序在100%非托管的操作系统上运行。如果使用文件,则使用操作系统资源。网络连接。一根线。控制台。等等,所有这些都是非常不受管理的资源

然而,这一事实在.NET中隐藏得相当清楚。框架库为这些本机对象提供了很好的包装类。文件流、套接字、线程、控制台等等。内存也是一种操作系统资源,垃圾收集器是它的包装器

在所有这些资源中,只有内存资源是真正自动管理的。其余的人都得到了奖章