简体   繁体   English

我们在C#中有非托管资源吗?

[英]Do we have Unmanaged resources in C#?

I had a discussion with my friend about managed and unmanaged resources in c#. 我和朋友讨论了C#中的托管和非托管资源。

According to my friend: 根据我的朋友:

1.a) Every object in C# is managed and there is nothing like unmanaged object or resource when we code in C#. 1.a)C#中的每个对象都是托管对象,当我们用C#编写代码时,没有像非托管对象或资源那样的东西。 Unmanaged resource concept comes only with C++. 非托管资源概念仅随C ++一起提供。

1.b) Whether we have managed or unmanaged resource in C++ we need to free it explicitly. 1.b)无论我们在C ++中是托管资源还是非托管资源,我们都需要显式释放它。 Since we have automatic garbage collector in C# we need need not think about managing resources. 由于我们在C#中具有自动垃圾收集器,因此无需考虑管理资源。

According to me: 据我说:

2.a)If we do not have unmanaged resource then why do we need a finalizer or Dispose method in C#? 2.a)如果我们没有非托管资源,那为什么我们需要C#中的finalizer或Dispose方法?

2.b)Garbage collector only has information about allocated memory and not about the state of the resources. 2.b)垃圾收集器仅具有有关已分配内存的信息,而没有资源状态的信息。 Therefore we need to use dispose method to release resources in C#. 因此,我们需要使用dispose方法释放C#中的资源。

I need help in understanding which of the above arguments are correct and information about unmanaged resource in c#, whether they exist or not? 我需要帮助来了解上述哪些参数正确,以及有关c#中非托管资源的信息,无论它们是否存在?

Thanks in Advance. 提前致谢。

No, it is impossible to write a C# program without using unmanaged resources. 不,如果不使用非托管资源就不可能编写C#程序。 It is inevitable, a C# program runs on an operating system that is 100% unmanaged. C#程序不可避免地在100%非托管的操作系统上运行。 If you use a file then you use an operating system resource. 如果使用文件,则使用操作系统资源。 A network connection. 网络连接。 A thread. 一个线程。 The console. 控制台。 Etcetera, all very much unmanaged resources. Etcetera,所有非常多的非托管资源。

That fact is however hidden pretty well in .NET. 但是,该事实在.NET中隐藏得很好。 The framework library has nice wrapper classes for these native objects. 框架库为这些本机对象提供了不错的包装器类。 FileStream, Socket, Thread, Console, etcetera. FileStream,Socket,线程,控制台等。 Memory is an operating system resource too, the garbage collector is a wrapper around it. 内存也是操作系统资源,垃圾回收器也是它的包装器。

Of all of these resources, only the memory resource is truly automatically managed. 在所有这些资源中,只有内存资源才真正被自动管理。 The rest of them get some measure of help by virtue of their wrapper class. 他们中的其他人凭借其包装器类获得了一定程度的帮助。 Their finalizer is the key, it releases the operating system resource when it is called. 它们的终结器是关键,它在调用时释放操作系统资源。 That's pretty close to automatic, the garbage collector notices that the wrapper class object is no longer referenced anywhere so it releases it, the finalizer then ensures that the unmanaged resource is released as well. 这几乎是自动的,垃圾回收器注意到包装类对象不再在任何地方引用,因此它释放它,然后终结器确保也释放非托管资源。

That usually works well, you can often ignore these implementation details in your code. 通常效果很好,您通常可以在代码中忽略这些实现细节。 Many programmers do. 许多程序员都这样做。

There is a problem with finalizers though, they take a while to start running. 不过,终结器存在问题,它们需要一段时间才能开始运行。 It takes a garbage collection to get them started, that can take anywhere from a handful of milliseconds to minutes. 要启动它们,需要进行垃圾收集,这可能需要花费几毫秒到几分钟的时间。 It is unpredictable, it depends on the rate in which you consume memory in your code. 这是不可预测的,取决于您在代码中消耗内存的速率。 If you don't use a lot of it then it will take a long time. 如果您不大量使用它,则会花费很长时间。

You cannot always afford to wait that long for an unmanaged resource to get released. 您不能总是承受这么长时间来等待释放非托管资源。 A file is a good example. 文件是一个很好的例子。 When you open one to read data from the file then you really should close the file when you're done reading. 当您打开一个文件来读取文件中的数据时,您确实应该在完成读取后关闭文件。 If you wait until the finalizer gets that job done then you run the risk of your program failing when it needs to open the file again, some time later. 如果等到终结器完成该工作,则可能会在程序需要一段时间后再次打开文件时冒程序失败的风险。 You might have locked yourself out by opening the file with FileShare.None, it locks your own code out as well. 您可能已经通过使用FileShare打开文件将自己锁定了。无,它也会锁定您自己的代码。 No big deal: you call Close() to close the file when you're done reading. 没什么大不了的:读取完成后,您可以调用Close()关闭文件。 To be sure it gets closed, you should put the Close() call in a finally block so it runs even if the code aborts due to an exception. 为确保关闭,您应该将Close()调用放在finally块中,以便即使代码由于异常中止而运行。 In effect, you run the finalizer code explicitly. 实际上,您显式运行终结器代码。

A more serious case is an operating system resource that is very expensive. 更严重的情况是非常昂贵的操作系统资源。 Good examples of those are bitmaps, they can take a lot of unmanaged memory, or database connections, there is a pool for them that by default only contains 100 of them. 位图就是一个很好的例子,它们可能占用大量非托管内存或数据库连接,它们的一个池默认情况下仅包含100个。 For these, you can get yourself well into a situation where letting the finalizer take care of releasing the resource just doesn't work because it takes too long. 对于这些,您可以使自己处在这样的情况下:让终结器负责释放资源,因为它花费的时间太长而无法工作。 Your program dies on an exception before the finalizer can run. 在终结器可以运行之前,您的程序死于一个异常。 Usually pretty hard to diagnose because that tends to only happens when your program is under load. 通常很难诊断,因为这往往仅在程序加载时才会发生。 Always hard to debug problems that occur when lots of things are going on, on a machine that is not on your desktop. 在台式机以外的计算机上,当发生许多事情时,总是很难调试发生的问题。

The .NET designers recognized this need and designed the IDisposable interface. .NET设计人员意识到了这一需求,并设计了IDisposable接口。 Its Dispose() method was designed to run the code that normally is run by the finalizer, giving you a way to explicitly releasing a resource rather than waiting for the garbage collector to get around to it. 它的Dispose()方法旨在运行通常由终结器运行的代码,从而为您提供一种显式释放资源的方法,而不是等待垃圾收集器处理它的方法。 And the language designers jumped on that bandwagon by adding the using keyword to their language, ensuring that IDisposable.Dispose() is automatically called. 语言设计者通过在他们的语言中添加using关键字来赶上潮流,确保自动调用IDisposable.Dispose()。

Using using or Dispose() in your code for any object that implements IDisposable is optional, as explained above, but considered vital by many .NET programmers. 如上所述,在代码中对实现IDisposable的任何对象使用using或Dispose()是可选的,但许多.NET程序员认为这很重要。 Mostly because everybody started .NET programming without it and ran into a problem sooner or later when their programs got big. 主要是因为每个人都开始没有它的.NET编程,而当他们的程序变大时,迟早会遇到问题。 It is even prescribed on classes where calling Dispose() makes no sense, like MemoryStream. 甚至在不调用Dispose()的类上也有规定,例如MemoryStream。 And causes mental anguish when a class should implement IDisposable but doesn't, like Thread. 当类应该实现IDisposable但不能实现IDisposable时,这会引起精神上的痛苦,例如Thread。 Or when a class implements both Dispose and Close (it makes no difference). 或者,当一个类同时实现Dispose和Close时(没有区别)。 For comparison, Java has the same considerations but doesn't have IDisposable. 为了进行比较,Java具有相同的考虑因素,但没有IDisposable。

Objects created in .NET are managed code but your objects can hold a reference to unmanaged ressources . 在.NET中创建的对象是托管代码,但是您的对象可以保存对非托管资源的引用 Garbage collector (GC) makes sure any memory allocated on the managed heap is cleaned up after it is no longer needed. 垃圾收集器(GC)确保不再需要在托管堆上分配的所有内存,然后再清理它们。 However, while the garbage collector is great at making sure that memory does not leak, it doesn't have any knowledge about other resources that need to be freed. 但是,尽管垃圾收集器非常擅长确保内存不泄漏,但它对需要释放的其他资源一无所知。 For instance, the garbage collector doesn't know how to close a file handle or how to release memory allocated outside of the managed heap with an API such as CoAllocTaskMem. 例如, 垃圾收集器不知道如何使用诸如CoAllocTaskMem之类的API 关闭文件句柄或如何释放在托管堆之外分配的内存

Objects that manage these types of resources must ensure that they are released when they're no longer needed. 管理这些类型的资源的对象必须确保在不再需要它们时将其释放。 You can accomplish this by overriding the Finalize method of System.Object, which lets the garbage collector know that the object would like to participate in its own cleanup (in C# you use the C++ destructor syntax, ~MyObject, rather than directly overriding the method). 您可以通过重写System.Object的Finalize方法来实现此目的,该方法使垃圾收集器知道该对象希望参与其自身的清理(在C#中,您使用C ++析构函数语法〜MyObject,而不是直接重写该方法)。 If a class has a finalizer, then before objects of that type are collected the garbage collector will call the object's finalizer and allow it to clean up any resources that it may be holding onto. 如果一个类具有终结器,则在收集该类型的对象之前,垃圾收集器将调用该对象的终结器,并允许其清除它可能持有的所有资源。

One problem with this system is that the garbage collector does not run deterministically and, as a result, your object may not be finalized for a long time after the last reference to it has gone away. 该系统的一个问题是,垃圾收集器无法确定性地运行,因此,在最后一次引用该对象之后,您的对象可能很长时间无法完成。 If your object holds onto an expensive or rare resource, such as a database connection, this may not be acceptable. 如果您的对象保留了昂贵或稀有的资源(例如数据库连接),则可能不可接受。 For instance, if your object has 1 of only 10 available connections open, it should release that connection as soon as possible, rather than waiting for the garbage collector to call the finalize method. 例如,如果您的对象只有10个可用连接中的1个处于打开状态,则它应尽快释放该连接,而不是等待垃圾回收器调用finalize方法。

For that you have a IDisposable interface that you should implement. 为此,您具有应实现的IDisposable接口。 Read more about it. 进一步了解它。

a) Every object in C# is managed and there is nothing like unmanaged object or resource when we code in C#. a)C#中的每个对象都是托管对象,当我们用C#编写代码时,没有像非托管对象或资源那样的东西。 Unmanaged resource concept comes only with C++. 非托管资源概念仅随C ++一起提供。

This is incorrect. 这是不正确的。 We can have unmanaged resources from from outside C# (eg COM), as others have mentioned. 正如其他人所提到的,我们可以从C#外部(例如COM)获得非托管资源。

However, it is certainly possible to have "unmanaged resources" in C# without accessing unmanaged code. 但是,当然可以在C#中拥有“非托管资源”而无需访问非托管代码。 These resources may not be unmanaged in the strict sense of garbage collection, but they are resources that you, as the developer, must handle cleaning up. 从严格的垃圾收集角度来看,这些资源可能不是不受管理的,但它们是开发人员必须处理的资源。 Take a thread for example: 以一个线程为例:

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();
}

Suppose the additional code returns or throws an exception. 假设其他代码返回或引发异常。 If you do not explicitly call StopThread, the thread executing DoLotsOfWork will not end, and your process will likely not exit. 如果您未明确调用StopThread,则执行DoLotsOfWork的线程将不会结束,并且您的进程可能不会退出。

b) Whether we have managed or unmanaged resource in C++ we need to free it explicitly. b)无论我们在C ++中是托管资源还是非托管资源,我们都需要显式释放它。 Since we have automatic garbage collector in C# we need need not think about managing resources. 由于我们在C#中具有自动垃圾收集器,因此无需考虑管理资源。

We absolutely must consider managing resources in C#. 我们绝对必须考虑使用C#管理资源。 This is why IDisposable exists, as you suggest. 正如您所建议的,这就是IDisposable存在的原因。

Consider this modification to the above code: 考虑对上面的代码进行此修改:

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...
    }
}

Now we can be sure that no matter what the additional code does, the thread created by the Foo class will be stopped before the process exits. 现在我们可以确定,不管附加代码做什么,由Foo类创建的线程都将在进程退出之前停止。

Every thing you create under the .net Framework is Mananged code and so the memeory consume by the object created by using .net framework manager by framework only. 在.net Framework下创建的所有内容都是Mananged代码 ,因此内存仅由通过使用.net Framework Manager(按框架)创建的对象使用。

Every thing which get created outside the .net framwork is unmanaged code. 在.net框架之外创建的所有事物都是非托管代码。

You can use finalizer or dispose when you want to relase the hevy object like you need to close the files or you are usning graphics and you want to release memory associated with it you can use this methods. 当您要释放沉重的对象(如需要关闭文件)或使用图形并且要释放与其关联的内存时,可以使用终结器或处置。可以使用此方法。

It is true that all objects created in the CLR are managed by the CLR, so you don't need to care about them. 的确,在CLR中创建的所有对象都是由CLR管理的,因此您无需关心它们。

However when you start using resources external to the CLR (a COM object for example, or a lock on a device) it is your responsibility to free those resources. 但是,当您开始使用CLR外部的资源(例如,COM对象或设备上的锁)时, 您有责任释放这些资源。 The CLR cannot do it for you, but provides the IDisposable interface to let you write code that does the cleanup. CLR无法为您完成此操作,但是提供了IDisposable接口,可让您编写进行清理的代码。

We do have to deal with unmanaged resourses in .NET. 我们确实必须处理.NET中的非托管资源。 A good example, is a connection to a database. 一个很好的例子是与数据库的连接。

We have to explicitly close that unmanaged resource. 我们必须显式关闭该非托管资源。 This is an example of why we have Dispose in C#. 这是为什么我们在C#中拥有Dispose一个示例。

An object which holds unmanaged resources puts other entities into a somewhat undesirable state (eg making them unavailable for other purposes) until it is told that it is no longer needed. 拥有非托管资源的对象将其他实体置于某种不可取的状态(例如,使其无法用于其他目的),直到被告知不再需要该实体为止。 If it is abandoned without first having been told that it is no longer needed, those other entities will be left in the undesirable state. 如果在没有先被告知不再需要它的情况下放弃了它,那么其他实体将处于不希望的状态。

A managed resource is an entity which similarly puts other entities into a somewhat-undesirable state until it is told it is no longer needed, but it will eventually automatically clean itself up if all "deliberate" references to it are abandoned. 受管资源是一个实体,它类似地将其他实体置于某种不希望的状态,直到被告知不再需要它为止,但是如果放弃了对它的所有“故意”引用,它最终将自动清理自身。

Event subscriptions from long-lived objects exist entirely within managed code, but because they are not cleaned up automatically during the lifetime of the long-lived objects, they should be regarded as unmanaged resources. 长期对象的事件订阅完全存在于托管代码中,但是由于在长期对象的生存期内不会自动清除它们,因此应将其视为非托管资源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM