What's the deal with declaring something static

We have a few customer who are using statics and not really understanding what they are creating.  There is a very good explanation at:
https://msdn2.microsoft.com/en-us/library/98f28cdx(VS.71).aspx

The summary of the important parts of that are:

  1. Use the static modifier to declare a static member, which belongs to the type itself rather than to a specific object.
  2. A static member cannot be referenced through an instance.
  3. While an instance of a class contains a separate copy of all instance fields of the class, there is only one copy of each static field.
  4. To demonstrate instance members, consider a class that represents a company employee. Assume that the class contains a method to count employees and a field to store the number of employees. Both the method and the field do not belong to any instance employee. Instead they belong to the company class. Therefore, they should be declared as static members of the class.

So now lets talk about the common mistake that is made.  First we create a class like:

 public class MyClass
{
    public static Dictionary myDictionary;
    MyClass()
    {
        
    }
}

Let's say we create the MyClass object, when we have a user hit a page on our site.  And we are going to store some data in the dictionary, say 10 items.  We add our information and then after we are done with the class, we do something like MyClassObj = null to get rid of the object.

The important thing to note here is #3 above, so even though your object goes away, the static members stay around.  So the next time the page is hit, we will add 10 more items to the existing dictionary and this will continue and the dictionary will grow.

Troubleshooting

So how does this end up looking in the debugger?  Well we will see a lot of strings or whatever the object type is that is being stored in the Dictionary on the heap and then we can use !gcroot to try see why this object is still around, and what will will find is something like:

 DOMAIN(00174428):HANDLE(Pinned):49911f0:Root:  28054110(System.Object[])->
  1c16f0f0(System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],
 [System.Collections.Generic.List`1[[System.ServiceModel.ICommunicationObject
 , System.ServiceModel]], mscorlib]])->
  2c0c00a8(System.Collections.Generic.Dictionary`2+Entry[[System.Int32,
 mscorlib],[System.Collections.Generic.List`1[[System.ServiceModel.
 ICommunicationObject, System.ServiceModel]], mscorlib]][])->
  1855d6e4(System.Collections.Generic.List`1[[System.ServiceModel.
 ICommunicationObject, System.ServiceModel]])->
  1855d6fc(System.Object[])->
  1854a5f8
...
  1854f1a8(System.Collections.Generic.Dictionary`2+Entry[[System.Type,
 mscorlib],[System.ServiceModel.Description.ContractDescription, System.
 ServiceModel]][])->
  1854a704(System.ServiceModel.Description.ContractDescription)->
  1854a77c(System.ServiceModel.Description.OperationDescriptionCollection)->
  1854a78c(System.Collections.Generic.List`1[[System.ServiceModel.
 Description.OperationDescription, System.ServiceModel]])->
  1854d5c8(System.Object[])->
  1854d0c4(System.ServiceModel.Description.OperationDescription)->
  1854d134(System.ServiceModel.Description.MessageDescriptionCollection)->
  1854d144(System.Collections.Generic.List`1[[System.ServiceModel.
 Description.MessageDescription, System.ServiceModel]])->
  1854d458(System.Object[])->
  1854d4b0(System.ServiceModel.Description.MessageDescription)->
  1854d248(System.String)

As you can see from this, there is no easy way to tell where this dictionary is coming from or what we should do about it.  Sometimes we can get lucky and find it while it is being added to, but that would be lucky.  Other then that, all we can do is look at the data inside it and try to tell what it is from that.  The best solution is to understand what you are creating and how it will be handled by .NET so you don't get into a situation like this.

Additional Static References:

https://www.ondotnet.com/pub/a/dotnet/2003/07/07/staticxtor.html