Docs: Not all unmanaged types are unmanaged resources or Unmanaged objects?

Created on 13 Nov 2019  ·  5Comments  ·  Source: dotnet/docs

As you say, int is an unmanaged type and generally we need to free unmanaged resources manually. But obviously we can not free an int manually. So what the precise definition of unmanaged resources? Is int one of the unmanaged resources? Is System.Drawing.Image or System.IO.FileStream one of the unmanaged resources? (I know they contains unmanaged resources)


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

Area - C# Guide product-question

Most helpful comment

Unmanaged types don't need garbage collection as they inherently disappear as the object owning them is garbage collected. This is why when an unmanaged type is used to track an unmanaged resource (such as a file handle) you have to implement your own cleanup, but you're not cleaning up the unamanged type, you're cleaning up the unmanaged resource.

For example, a class:

class GraphicsCardTexture   // <- managed type, will be handled by GC eventually
{
    ImageData Image; // <- managed type, will be handled by GC eventually

    public GraphicsCardTexture(string filename)
    {
        // Some code here that opens the image and uploads it to the graphics card.
        // It returns you the location of the image in the graphics card and the width/height of the image.
        Image = LoadIntoGraphicsCard(filename);
    }

    // Finalizer <- called by GC when the GC cleans up this class.
    ~GraphicsCardTexture()
    {
        // this is cleanup of the unmanaged resource (the graphics card image) notice that
        // we used the unamanged type (long, the GraphicsCardMemoryLocation)
        UnloadGraphicsCardImage(Image.GraphicsCardMemoryLocation);
    }
}

class ImageData // <- managed type, will be handled by GC eventually
{
    // These three below are unamnaged types. They are handled automatically when the
    // GC handles this class itself.
    public int Width;
    public int Height;
    public long GraphicsCardMemoryLocation;
}

In this example when you create a new GraphicsCardTexture instance, you've uploaded a graphic to the graphics card. The thing that needs to be cleaned up is not the GraphicsCardMemoryLocation _unmanaged type_ variable, but the data on the graphics card. This data on the graphics card becomes the unmanaged resource and this is what you need to clean up. The _unmanaged type_ is just a thing you're using which may or may not represent an unmanaged resource, such as Width/Height. These don't happen to be pointing to any sort of unmanaged resource.

As you read in Cleaning Up Unmanaged Resources:

Override the Object.Finalize method. Finalization enables the non-deterministic release of unmanaged resources when the consumer of a type fails to call IDisposable.Dispose to dispose of them deterministically. However, because object finalization can be a complex and error-prone operation, we recommend that you use a safe handle instead of providing your own finalizer.

So in this example you don't necessarily want to rely on the finalizer like I did in the GraphicsCardTexture class. If the GC waits 20 minutes after you've used the texture to clean up the memory, the graphics card still has an image on it for those 20 minutes, even though you don't need it anymore. If something terminates your app abruptly, the finalizer may not be called, and now the graphics card memory may not be cleaned up. This is what the Dispose pattern solves. It provides you a pattern to clean up unmanaged resources right away when you're done with it, and you implement that pattern in such a way that the finalizer becomes the backup incase the coder who used your code doesn't call Dispose when they are finished with your object.

All 5 comments

@akimusume Hello!

You can conceptually think of an unmanaged type as different than an unmanaged resource. Types such as System.Drawing.Image or System.IO.FileStream are managed types because they are declared as class. When a managed type is done being used, the garbage collector comes by (eventually) and frees up the memory used by that object. However, in the case of something like System.Drawing.Image, it is using an unmanaged resources behind the scenes and the garbage collector doesn't know about that. This is why you explicitly free those resources prior to the object getting handled by the garbage collector. This is what the Dispose pattern helps handle.

It really comes down to what the object is doing with the unmanaged types. How was it holding on to that memory represented by the unmanaged type? Unamanged types don't typically need to be freed unless you've used it in such a way that the unmanaged type represents some sort of unmanaged resource like a file handle or a texture on a graphics card. You want to make sure that the memory this unmanaged type represents is closed and freed up. This is what the System.Drawing.Image or System.IO.FileStream do, they are using unmanaged types to represent the file handles (and they now are considered an unmanaged resource). If the garbage collector destroys the System.IO.FileStream class instance, as far as the operating system (OS) is concerned, the file handle the OS opened for the class was never closed.

Put simply, unmanaged types are generally freed automatically as the owning method (or object) goes out of scope. .NET understands the memory footprint of a methods and types. Variables created in a method or an object type (even an unmanaged type variable) are all automatically freed when the method finishes executing or when the garbage collector destroys the object. If the unmanaged type variable was used in such a way as representing something .NET doesn't know about, that isn't cleaned up automatically and you need to make sure you clean it up.

@BillWagner please correct me, you're the expert here but I wanted to take a shot at answering this.

I'm going to close this issue as I think this helps you understand it. Feel free to reopen or continue discussing it. Cheers!

Huge thanks to your detailed reply. Now I know their difference. Their names are really confusing.
Maybe you should add some notes to this document and the Cleaning Up Unmanaged Resources for I can not find any other document mentions "Unmanaged types" except this and nowhere describes the garbage collection for them.

Unmanaged types don't need garbage collection as they inherently disappear as the object owning them is garbage collected. This is why when an unmanaged type is used to track an unmanaged resource (such as a file handle) you have to implement your own cleanup, but you're not cleaning up the unamanged type, you're cleaning up the unmanaged resource.

For example, a class:

class GraphicsCardTexture   // <- managed type, will be handled by GC eventually
{
    ImageData Image; // <- managed type, will be handled by GC eventually

    public GraphicsCardTexture(string filename)
    {
        // Some code here that opens the image and uploads it to the graphics card.
        // It returns you the location of the image in the graphics card and the width/height of the image.
        Image = LoadIntoGraphicsCard(filename);
    }

    // Finalizer <- called by GC when the GC cleans up this class.
    ~GraphicsCardTexture()
    {
        // this is cleanup of the unmanaged resource (the graphics card image) notice that
        // we used the unamanged type (long, the GraphicsCardMemoryLocation)
        UnloadGraphicsCardImage(Image.GraphicsCardMemoryLocation);
    }
}

class ImageData // <- managed type, will be handled by GC eventually
{
    // These three below are unamnaged types. They are handled automatically when the
    // GC handles this class itself.
    public int Width;
    public int Height;
    public long GraphicsCardMemoryLocation;
}

In this example when you create a new GraphicsCardTexture instance, you've uploaded a graphic to the graphics card. The thing that needs to be cleaned up is not the GraphicsCardMemoryLocation _unmanaged type_ variable, but the data on the graphics card. This data on the graphics card becomes the unmanaged resource and this is what you need to clean up. The _unmanaged type_ is just a thing you're using which may or may not represent an unmanaged resource, such as Width/Height. These don't happen to be pointing to any sort of unmanaged resource.

As you read in Cleaning Up Unmanaged Resources:

Override the Object.Finalize method. Finalization enables the non-deterministic release of unmanaged resources when the consumer of a type fails to call IDisposable.Dispose to dispose of them deterministically. However, because object finalization can be a complex and error-prone operation, we recommend that you use a safe handle instead of providing your own finalizer.

So in this example you don't necessarily want to rely on the finalizer like I did in the GraphicsCardTexture class. If the GC waits 20 minutes after you've used the texture to clean up the memory, the graphics card still has an image on it for those 20 minutes, even though you don't need it anymore. If something terminates your app abruptly, the finalizer may not be called, and now the graphics card memory may not be cleaned up. This is what the Dispose pattern solves. It provides you a pattern to clean up unmanaged resources right away when you're done with it, and you implement that pattern in such a way that the finalizer becomes the backup incase the coder who used your code doesn't call Dispose when they are finished with your object.

Thanks a lot. It's really helpful. 👍👍

Was this page helpful?
0 / 5 - 0 ratings

Related issues

garfbradaz picture garfbradaz  ·  3Comments

Eilon picture Eilon  ·  3Comments

gmatv picture gmatv  ·  3Comments

JagathPrasad picture JagathPrasad  ·  3Comments

ygoe picture ygoe  ·  3Comments