Static constructors/destructors

G

Guest

I know how to create and use static constructors, but is there a such thing
as a static destructor?

If not, then how do you deallocate memory intialized in the static
constructor?

Thanks in advance,
Joe
 
A

Abhijeet Dev

Static constructor is executed when a class is referenced for the first
time, any static data in a process will(/must) remain in memory until
the process is killed - static data in a running process can not be
destructed and it will always be destructed when the process exits.
Static constructor in .Net initializes static data, it is possible
because compiled assembly is just a stub of the executing native
assembly and the code is JIT compiled and filled in there.
Just try to match the situation with any language which compiles to
native assembly, static data must be initialized as soon as the assembly
is loaded in memory.
 
B

Brandon Bray [MSFT]

Abhijeet said:
Static constructor is executed when a class is referenced for the first
time, any static data in a process will(/must) remain in memory until
the process is killed - static data in a running process can not be
destructed and it will always be destructed when the process exits.
Static constructor in .Net initializes static data, it is possible
because compiled assembly is just a stub of the executing native
assembly and the code is JIT compiled and filled in there.
Just try to match the situation with any language which compiles to
native assembly, static data must be initialized as soon as the assembly
is loaded in memory.

To add more clarity about some specific cases... the static constructor is
not constructing an object, but rather assigning values to static members
before they are used. Therefore, it doesn't quite make sense to match a
static constructor with a single destructor.

Those static members could be types that need destruction. Managed types
assigned to a static variable will rely on the finalizer to clean up
resources.
 
G

Guest

I have a c++.NET 2003 class library that has a class with the following basic
structure, with a static constructor that initializes unmanaged memory;
mainly char*s that I need to pass to unmanaged functions (c functions,
structures, etc) (where I have to __pin).

Arent the char*s below declared unmanaged and therefore need to be deleted?

public __gc class EAHConnection : public IEAHConnection
{

protected:
static String* m_defaultConnectionString;
static int m_defaultDnsTimeout;
static char* m_domainIsamPath;
static char* m_domainDatPath;

static EAHConnection()
{
m_defaultDnsTimeout = Int32::parse(reader->Value);
m_defaultConnectionString = String::Copy(reader->Value);

m_domainIsamPath = (char*)(void*)Marshal::StringToHGlobalAnsi(
reader->Value);
m_domainDatPath = (char*)(void*)Marshal::StringToHGlobalAnsi(
reader->Value);
}

}


Dont I have to free those variables somewhere? Like...

Marshal::FreeHGlobal((int)m_domainIsamPath);
Marshal::FreeHGlobal((int)m_domainDatPath);


Thank you very much for effort and help.

Joe
 
A

Abhijeet Dev

Any static field is deleted when the process exits or is killed. Static
fields go to the text segment of process memory rather than data
segment. Object instances (and member fields) go to the data segment and
anything in data segment must be freed as soon as process frees an
object pointer. You write destructor for things in data segment, never
for anything in text segment. Text segment includes
instructions,class-definition, static constants etc.
If a static field is subject to change, I am not sure, but the pointer
to it should be in text segment and the memory should be allocated on
stack/heap depending on it's type, even in that case the pointer can not
be dereferenced and so, the memory used by static fields will never be
deleted in process lifetime. You can check these facts better by using a
profiler.
 
B

Brandon Bray [MSFT]

Joe said:
Dont I have to free those variables somewhere? Like...

Marshal::FreeHGlobal((int)m_domainIsamPath);
Marshal::FreeHGlobal((int)m_domainDatPath);

If the resources belong to the process (or the AppDomain as the case may
be), they could be freed by OS or the runtime. If the resource is not
managed by the runtime, and you want to release the resource when an
AppDomain shuts down, you can register a delegate with the
System::AppDomain::DomainUnload event.

That's only necessary if the static member doesn't have a finalizer (such as
a char*).
 
B

Brandon Bray [MSFT]

Joe said:
Does that mean I have to implement the Finalize (or is it Dispose)
method?

If the resource the static member refers to is a ref class, that ref class
should implement a finalizer if it has resources to clean up.
 
B

Brandon Bray [MSFT]

Abhijeet said:
Any static field is deleted when the process exits or is killed. Static
fields go to the text segment of process memory rather than data
segment. Object instances (and member fields) go to the data segment and
anything in data segment must be freed as soon as process frees an
object pointer. You write destructor for things in data segment, never
for anything in text segment. Text segment includes
instructions,class-definition, static constants etc.

While all of that is true for unmanaged code, it is different for managed
types. Static objects are allocated on the GC heap just like other dynamic
objects. That is true even if they are global static objects. The
C++-runtime library and the CRT coordinate to ensure the best semantics for
the memory management of these objects.

Static variables do need cleanup if they are managing a resource that
persists beyond the process lifetime (or the AppDomain lifetime). If the
variable is initialized at startup (as is the case with global variables),
the CRT registers the destructor for each object so they are cleaned up at
shut down. That is not the case for static constructors. If the static
constructor initializes a ref class, it is the finalizers responsibility to
clean up. If the static constructor initializes a value class, extra work
must be done to register clean up with the shut down event. Ideally, a ref
class would be used to abstract those resources.
 
G

Guest

So Im a little confused... in my case, where the static constuctor sets a
char* via Marshal::StringToHGlobalAnsi, do I need to register a delegate with
the
System::AppDomain::DomainUnload event to clean up this resource?

Thanks for all your help!

Joe
 
B

Brandon Bray [MSFT]

Joe said:
So Im a little confused... in my case, where the static constuctor sets
a char* via Marshal::StringToHGlobalAnsi, do I need to register a
delegate with the System::AppDomain::DomainUnload event to clean up
this resource?

Since the documentation topic doesn't say anything specific to AppDomains,
you would need to register your own cleanup code if you wanted to avoid
leaking resources when an AppDomain unloads. If you're not using AppDomains
(i.e. only concerned about process shutdown), you don't need to worry about
cleaning up memory since the OS will reclaim all the memory anyways.
Thanks for all your help!

No problem. :)
 
A

Abhijeet Dev

Thanks for the eye-opener.
This part of CLR memory management I can understand now, but it still
leaves few things popping-up in my mind :(

1. What kind of resources we must clean-up on AppDomain unload event. As
you mentioned in another message, clean-up of static variables with
managed type will rely on the finalizer(types'). So, static variables of
managed type we are not concerned about, assuming they are well-written.
If we have unmanaged memory e.g. char *(as you mentioned), when we try
to store something here, we request some memory from the OS memory
manager, it will be in use till the process is running, but when the
process exits, that part of memory is free. What a process is using is
Process Heap. As soon as the process is gone, the process heap is gone.
I understand that there must be some type of resources which may require
this clean-up process, but why memory? (or security implications?)

2. What I understand is, JIT compiler must be inserting code here and
there to allocate everything on the process heap and the process static
data is part of the stub every .Net assembly is bound to have and that
the details would be more clear by analyzing the ngen'ed image(trying,
but finding it close to impossible) rather than IL. AppDomain lifetime
is subset of the process lifetime, and if a resource remains referenced
by some part of the code in AppDomain lifetime, it still has to be freed
when the process lifetime is over?

4. How should we clean-up the resources accrued by static initialization
in a MarshalByRef singleton class, when used in an application with
multiple AppDomains?
(This is a bit too specific, but it seems to be the exception to this
idea, and what if it really comes up some day)
 
B

Brandon Bray [MSFT]

Hey Abhijeet... great questions!

Abhijeet said:
1. What kind of resources we must clean-up on AppDomain unload event. As
you mentioned in another message, clean-up of static variables with
managed type will rely on the finalizer(types'). So, static variables of
managed type we are not concerned about, assuming they are well-written.
If we have unmanaged memory e.g. char *(as you mentioned), when we try
to store something here, we request some memory from the OS memory
manager, it will be in use till the process is running, but when the
process exits, that part of memory is free. What a process is using is
Process Heap. As soon as the process is gone, the process heap is gone.
I understand that there must be some type of resources which may require
this clean-up process, but why memory? (or security implications?)

If we're only concerned about cleaning up when the process finishes, then
there's no real concern about freeing memory. The OS will reclaim the memory
as you said.

When we're dealing with AppDomains, it's trickier. Because an AppDomain
creates a fake process within the OS's real process, the OS doesn't have the
ability to wipe clean all of the resources when a single AppDomain shuts
down and others continue to run. If a finalizer or some other cleanup
registered with the AppDomain unload event doesn't clean up the resources,
they will be tied up until the process ends. That means the other AppDomains
running inside the process will be starved for those resources.
2. What I understand is, JIT compiler must be inserting code here and
there to allocate everything on the process heap and the process static
data is part of the stub every .Net assembly is bound to have and that
the details would be more clear by analyzing the ngen'ed image(trying,
but finding it close to impossible) rather than IL. AppDomain lifetime
is subset of the process lifetime, and if a resource remains referenced
by some part of the code in AppDomain lifetime, it still has to be freed
when the process lifetime is over?

You're right that resources are freed when the process is over. That may or
may not coincide with the AppDomain shutdown. Analyzing code at compile time
isn't really possible. While the code might all be compiled, initialization
of static members of a class happens when that type is first used. (Note,
there are two modes for choosing when static data of a type is initialized,
but the type must be in use in both modes.) Since a type may only come in to
use on certain paths of execution, there's only a limited set of analysis
the JIT can do.
4. How should we clean-up the resources accrued by static initialization
in a MarshalByRef singleton class, when used in an application with
multiple AppDomains?
(This is a bit too specific, but it seems to be the exception to this
idea, and what if it really comes up some day)

Since Marshal By Ref objects cannot be a value type, you should be able to
write a finalizer. So, by making sure the finalizer works, there's no
concern with AppDomains.

If the finalizer cannot work, any static that creates the MBRO, would need
to register a clean up delegate with the AppDomain Unload event.

Hope that helps,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top