Virtual and non-virtual

The CLR type system supports both virtual and non-virtual instance methods.  And IL can contain both CALLVIRT and CALL instructions.  So it makes sense that IL generators would call virtual methods using CALLVIRT and call non-virtual instance methods with CALL. In fact, this is not necessarily the case. Either kind of call instruction can be applied to…

3

Interning Strings and immutability

Managed strings are subject to ‘interning’. This is the process where the system notices that the same string is used in several places, so it can fold all the references to the same unique instance. Interning happens two ways in the CLR.   It happens when you explicitly call System.String.Intern(). Obviously the string returned from…

22

Lifetime, GC.KeepAlive, handle recycling

It’s not possible to state exactly when a managed object will be collected. The garbage collector schedules itself based on various heuristics. Even if a garbage collection occurs, it may only collect the younger generations of the heap. And the JIT has some freedom to lengthen or shorten the lifetime of instances, based on how…

19

Managed blocking

What’s the difference between WaitHandle.WaitOne/WaitAny/WaitAll and just PInvoke’ing to WaitForSingleObject or WaitForMultipleObjects directly? Plenty. There are several reasons why we prefer you to use managed blocking through WaitHandle or similar primitives, rather than calling out to the operating system via PInvoke. First, we can blur any platform differences for you Do you know the differences…

9

ReleaseComObject

Developers who are accustomed to the IDisposable pattern or to C#’s ‘using’ syntax sometimes ask why COM Interop doesn’t support IDisposable on every Runtime Callable Wrapper (RCW). That way, managed code could indicate that it is finished using the unmanaged COM resource. This would allow the resources to be cleaned up much earlier than they…

14

Threads, fibers, stacks and address space

Every so often, someone tries to navigate from a managed System.Threading.Thread object to the corresponding ThreadId used by the operating system. System.Diagnostic.ProcessThread exposes the Windows notion of threads. In other words, the OS threads active in the OS process. System.Threading.Thread exposes the CLR’s notion of threads. These are logical managed threads, which may not have…

15

Initializing code

A common question is how to initialize code before it is called. In the unmanaged world, this is done with a DLL_PROCESS_ATTACH notification to your DllMain routine. Managed C++ can actually use this same technique. However, it has all the usual restrictions and problems related to the operating system’s loader lock. This approach is not…

5

Unhandled exceptions

There are two kinds of threads executing inside managed code:  the ones we start in managed code and the ones that wander into the CLR. The ones that started in managed code include all calls to Thread.Start(), the managed threadpool threads, and the Finalizer thread(s). For all the threads we start in managed code, the CLR has its own exception…

11

Inheriting from MarshalByRefObject

Developers often wonder why they are forced to derive from MarshalByRefObject or EnterpriseServices.ServicedComponent. It would be so much more convenient if they could add a CustomAttribute to their class or use a marker interface to declare that they want to be marshaled by reference or they want serviced behavior. The reason has to do with…

8

Managed objects and COM

All managed objects other than those derived from ServicedComponent, when exposed to COM, behave as if they have aggregated the free threaded marshaler (FTM). In other words, they can be called on any thread without any cross-apartment marshaling. Although managed objects act as if they aggregate the FTM, they don’t actually aggregate it because that…

10