44

I have a class with extensive static members, some of which keep references to managed and unmanaged objects.

For instance, the static constructor is called as soon as the Type is referenced, which causes my class to spin up a blockingQueue of Tasks. This happens when one of the static methods is called, for example.

I implemented IDisposable, which gives me methods to handle disposal on any instance objects I created. However, these methods are never called if the consumer doesn't create any instance objects from my class.

How and where do I put code to dispose of references maintained by the static portion of my class? I always thought that disposal of static-referenced resources happened when the last instance object was released; this is the first time I've ever created a class where no instances may ever be created.

Joe
  • 483
  • 1
  • 4
  • 7
  • 2
    Static items are available for the entire execution of the application. You don't create static items by using the NEW keyword, so this means you don't have multiple instances of anything, because you actually don't instantiate anything. About managed objects, don't worry about them, the GC will take care of them. About unmanaged resources try to use them in a non static class, or they will be kept until you close your application. Static items don't support dispose. – Alexandru Dicu Aug 25 '12 at 23:57
  • Is it reliable that statically referenced unmanaged resources will be released when the app exits? Let's say I have an OpenGL or OpenAL context that I want to just keep around until the app exits. Is there any reason not to just have a static class member reference to that context? – Shavais Nov 30 '22 at 23:38

4 Answers4

64

The static variable of your class are not garbage collected until the app domain hosting your class is unloaded. The Dispose() method will not be called, because it is an instance method, and you said that you wouldn't create any instances of your class.

If you would like to make use of the Dispose() method, make your object a singleton, create one instance of it, and dispose of it explicitly when your application is about to exit.

public class MyClass : IDisposable {
    public IList List1 {get; private set;}
    public IDictionary<string,string> Dict1 {get; private set;}
    public void Dispose() {
        // Do something here
    }
    public static MyClass Instance {get; private set;}
    static MyClass() {
        Instance = new MyClass();
    }
    public static void DisposeInstance() {
        if (Instance != null) {
            Instance.Dispose();
            Instance = null;
        }
    }
}
7three
  • 163
  • 13
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
9
public class Logger : IDisposable
{

    private string _logDirectory = null;
    private static Logger _instance = null;

    private Logger() : this(ConfigurationManager.AppSettings["LogDirectory"])
    {
        AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
    }

    private Logger(string logDirectory) 
    {
    } 

    public static Logger Instance
    {
        get
        {
            if (_instance == null)
                _instance = new Logger();
            return _instance;
        }
    }

    private void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        Dispose();
    }



    public void Dispose()
    {
        // Dispose unmanaged resources
    }
}
Xpleria
  • 5,472
  • 5
  • 52
  • 66
Guido Kleijer
  • 559
  • 1
  • 5
  • 7
1

You should dispose this objects manually, there is no way to create a "finalizer" for static resources.

oxilumin
  • 4,775
  • 2
  • 18
  • 25
  • 2
    How would I dispose of them manually? How will I be notified that I need to do this? – Joe Aug 25 '12 at 23:56
  • 1
    @Joe That is entirely up to you to decide. Only you know when it's time to call Dispose of something that is statically held. – vcsjones Aug 25 '12 at 23:58
  • For instance, see the example in original question, where I spin up a blockingQueue of Actions. This queue should run until the user no longer wants to drop Actions into it (via static method). Let me make that more clear; when do I kill off the task that drains that queue? So, when do I kill it? How will I know my class is no longer in "scope" to the user? – Joe Aug 25 '12 at 23:58
  • @Joe You can for example use static integer variable to store resource consumers count (increment/decrement it via `Interlocked` class in constructor/destructor/dispose method). – oxilumin Aug 26 '12 at 00:00
  • Let me clarify all of my edits above. In particular, I maintain a blockingQueue of Actions for a logger. When a user wants to have something logged, he calls my static method Log, and I drop an Action into the blockingQueue that calls the logger. I have a separate Task, created by my static constructor, which drains this queue. This queue and the task that drain it should remain in place "forever", or at least until my assembly is unloaded. So - when do I kill off this Task? Is there some notification that my assembly is no longer needed, so I can clean up the other (unmanaged) resources? – Joe Aug 26 '12 at 00:05
  • Only 6 years later.... Why not have the user tell you when they're finished? How else would you know that they're done using it? Or have a context object that encapsulates the disposable that the user disposes of when they're done. (Singletons are convenient, and for this reason they're often overused. I'm very guilty of that myself over the years.) – Dennis Estenson Oct 22 '18 at 20:15
  • A static field should be associated with a `Type` for the duration of your applications lifetime. In other words, the `object` is cleaned up when your application exits. If you have a static field that requires being cleaned up after an instance of your type has been disposed then you really shouldn't be using a `static` member in this case. – WBuck Dec 01 '20 at 15:39
-1

If you really want to have static members which keep references to unmanaged objects just create a method for disposing the unmanaged objects and "force" consumer to use it on exit.

By "force" I mean document your class with a paragraph that states "when" and "why" to use this "dispose" method. Do it either if you are the sole consumer (or your code...) or you plan to distribute your class. Also try to use a somehow descriptive name (to that "dispose" method) such as "DisposeStatics", "AlwaysDispose", "DisposeAtEnd" etc.

ilias iliadis
  • 601
  • 8
  • 15