As we all know, classes in .NET are passed by reference and structs by value.
In unsafe code, you can have pointers to structs, but not to classes since they are moved by the GC. When you have a pointer to an array, for example, you either have to put it in a fixed statement (if you allocated on the heap) or stackalloc (to allocate on the stack).
With that said, how is it possible for classes to be passed by reference if they are moved by the GC?
What the GC moveth; the GC fixeth. Since the GC has to find all references to an object anyway (to see if it's GC'able), it's a small extra step to change those references to point to the new address.
You can think of class type instance as a handle, then a reference to handle would be just one more indirection (sort of a pointer to handle) limited in scope by a method call. Since the object itself remains hidden behind a handle it can be relocated without any visible effect.
Related
I have a C# class, having a static ImageList object. This image list will be shared with various ListView headers (via SendMessage... HDM_SETIMAGELIST) on several forms in my application.
Though I understand that static objects are not eligible for garbage collection, it is not clear to me if they are also ineligible for relocation (compaction) by the garbage collector. Do I also need to pin this object since it is shared with unmanaged code, say, using GCHandle.Alloc?
Environment is VS 2008, Compact Framework 3.5.
The instance itself is not static. The reference is. If you null the reference the instance becomes eligible for GC. Internally, all static instances are references through a pinned handle to an array of statics. I.e. the instance is implicitly pinned by the runtime.
If you look at the GCroot of an instance declared as a static member, you'll see something like this:
HandleTable:
008113ec (pinned handle)
-> 032434c8 System.Object[]
-> 022427b0 System.Collections.Generic.List`1[[System.String, mscorlib]]
If you null the static reference the corresponding entry in the pinned array is nulled as well.
Now, these are obviously implementation details so they could potentially change.
Yes. You need to pin the object.
While it's true that the reference is static, that is, you may access this location anywhere from your member it's reference is still a GC handle. That is, it's eligible for garbage collection (and/or compaction) but it will of course never happen.
I don't think it's necessarily wrong to think that the static modifier implies that it will eventually have a static location in memory but there bigger issue is that there's no API that allows you to get at the memory address without pinning the object. Whether it's being moved by the GC or not.
Moreover, each static member is unqiue per AppDomain (not process). The same static member could exist in different memory locations in the same process and it can be garbage collected when the AppDomain unloads. This is quite the edge case I'll admit but there's no real advantage of not pinning objects even if it could be done without pinning.
Do I also need to pin this object since it is shared with unmanaged
code, say, using GCHandle.Alloc?
Yes. If the pointer is not pinned, GC is free to move that memory, so you may have dangling C++ pointers, pointing to some non valid, or worse, non their memory at all.
Also, "shared" word should be clarified. If you allocate and pass to unmanaged memory, which copies it somewhere, you may avoid to pin them constantly. Depends on what happens once you pass control to unmanaged environment.
EDIT
Even considering interesting answer from #Brian, I would still opt for pinning the pointer. To make explicit in the code the notion of the fixed pointer, avoid any possible misguide in future code maintenance and keep clarity.
I want to put a reference to a C# object into unmanaged memory (C), I guess as a pointer (int), and when the C code calls back into C# later on, I want to get the reference back from the unmanaged memory, so I can resolve it, and access the object. The reason is that the C code controls which object should be used, there's no real alternative. I have limited control over the C code and C++/CLI is not an option.
Question: Is that possible and safe, if so, how?
Well, it is possible. Primary concern is that your scheme is very incompatible with the garbage collector, it moves objects in memory when it compacts the heap. That's something you can stop, you can pin the object so the GC cannot move it. You use GCHandle.Alloc() to allocate a GCHandleType.Pinned handle and pass the return value of GCHandle.AddrOfPinnedObject() to your C code, presumably with a pinvoke call.
You have to fret about how long that object needs to stay pinned. A couple of seconds, tops, is okay, but it gets pretty detrimental to the GC if you keep it pinned for a long time. It is a rock in the road that the GC constantly has to drive around. And the heap segment can never be recycled, that single object can cost you a handful of megabytes.
In which case you should consider allocating unmanaged memory and copying the object into it. Use Marshal.AllocHGlobal() to allocate, Marshal.StructureToPtr() to copy the object into it. Possibly multiple times if you modify the object and the changes need to be visible to the C code as well.
Either way, the object must be blittable or you get a runtime error. An expensive word that just means that the object must have simple field types, the kind that a C program has a shot at reading correctly. Don't use bool. Be careful with the declaration in the C program, pretty easy to corrupt the heap when you get it wrong.
When you control the 'handing out' and the 'use after receiving back' phases you can simply use a List or array and pass around the index.
It's possible to consume C# objects via COM and proxies created by the CLR called COM-Callable Wrappers.
You just need assign a GUID assembly attribute to identify the COM type library, e.g.:
[assembly: Guid ("39ec755f-022e-497a-9ac8-70ba92cfdb7c")]
And then use the Type Library Exporter tool (tlbexp.exe) to genereate the COM type library (.tlb) file which can be consumed in the COM world:
tlbexp.exe YourLibrary.dll
If you mean safe in the C#'s sense of the word, then certainly unsafe, as you'll be using the objects in the unmanaged world, and lifetimes are controlled from the COM side via reference counting as opposed to CLR's GC.
I know that an instance variable of a class comes to life when a new instance of that class is instantiated and when there are no references to that instance, the instance's destructor has executed. But what about instance variables lifetime in structs?
Thanks.
and when there are no references to that instance, the instance's destructor has executed
Only if that class has a destructor (otherwise, its memory is simply reclaimed), if GC.SuppressFinalize hasn't been called on that object, and when the Garbage Collector decides to collect the generation to which that object belongs.
Also note that destroying an object isn't the same as reclaiming its memory.
When the GC calls an object's destructor, the object will be promoted to the next generation, and its memory will only be reclaimed the next time the GC decides to collect that generation, if there are still no strong references to it.
And this is why it's possible (but don't do it!) to resurrect an object, by creating a strong reference to itself (e.g., assigning itself to a static field) within the destructor.
But what about instance variables lifetime in structs?
If they're declared within a method and not leaked anywhere (such as using it in a closure, or being assigned to a field member), chances are they'll be put on the stack and deleted deterministically when the method ends, and the GC will never know about it.
If they're assigned to a field, they'll live as long as the enclosing class lives.
Also, structs can't have destructors.
First of all, it is not true, that if there are no references to the instance, it's destructor is being called. What really happens is that at the time of Garbage Collector's choice the object is marked as garbage and then later, again at the time of Garbage Collector's choice the object is destroyed.
In case of structures, you have to remember, that structure behaves similarly as any other value-type object (such as int, float and so on). So, for example, if you keep structure in a local variable and exit the method, structure is deleted from the stack, thus clearing all references to its all fields - and if they are reference-typed (and no other references exists), they will be collected by the GC in the same manner I described earlier. If they are value-typed, they are deleted immediately.
You can read more about this matter in article and on msdn
You should probably read up on Garbage Collection, as the assumptions you make are outright wrong. When nothing references an object, GC may collect it, but you won't know precisely when. Also, C# has no destructors, it has finalizers, which aren't deterministic as opposed to destructors. The syntax is the same as the C++ destructor, but under the hood they're different.
The difference between reference types (classes) and value types (structs), is that reference types are garbage collected if there is no valid reference to them anymore, where value types are collected when they go out of scope. Types like int, IntPtr, etc are all structs and follow the same rules.
As per MSDN:
"An instance variable of a struct has exactly the same lifetime as the struct variable to which it belongs i.e, when a variable of a struct type comes into existence or ceases to exist, so too do the instance variables of the struct."
Source: http://msdn.microsoft.com/en-us/library/aa691165(v=vs.71).aspx
(Although it is destroyed by the Garbage Collector actually).
I am in the situation where I have a c# object containing an HGLOBAL and a List<Delegate>. The HGLOBAL holds references to the delegates and the HGLOBAL is registered in unmanaged code as a callback (specifically, a vtbl-style interface).
I'm trying to not get bogged down in the details of the overall design (I'm already expecting some screaming from those that understand what I'm doing in the previous paragraph). My question is currently one of lifetime management using functions I wish were documented differently.
I have converted the class holding the HGLOBAL and the List<Delegate> into a subclass of SafeHandle (because of CriticalFinalizerObject and because HGLOBAL is kinda a handle), and I do have the class that is instantiating this using CER-style atomic transactions to inform C# when the unmanaged code stops expecting it to stick around.
Does calling DangerousAddRef effectively bump up a reference count for the entire SafeHandle object? Will the List<Delegate> be included in this reference count? Another way of asking this is whether DangerousAddRef is effectively constructing a GCHandle to the entire SafeHandle object, or whether it is doing so simply to the SafeHandle.handle member inside?
If it is not applying to the object as a whole then the List<Delegate> is likely to be collected early and cause access violations when unmanaged code tries to call into it.
If it is applying to the object as a whole then I have just created a block of reference-counted objects within a garbage-collected heap and I had better be darned sure that I haven't created any reference loops.
I suspect it's the latter, but there are very few Google searches on this kinda stuff, and when the only symptoms you're dealing with are unmanaged access violations from the finalizer thread on process shutdown when no actual managed code is being ran then it starts to get difficult to see whether you're going in the right direction.
What happen at background(in case of memory) when I declare variable and then create object for that variable . Is reference variable store anywhere and in which format and how this variable points to the memory on heap. Please clarify below doubts in the comments.
For example
ClassA instance; // Where this variable store and how much memory occupies
instance=new ClassA(); //How instance variable points to memory
EDIT
What will effect on my program memory if my program contains so many unused variable.
The instance variable is just a pointer at runtime, it points to the object allocated in the GC heap. The variable can live anywhere, stack, CPU register, inside another object that's on the heap or in the loader heap if it is static.
The big deal about the garbage collector is that it is capable of finding this pointer during a garbage collection. And can thus see that the object is still referenced and can adjust the pointer value when it compacts the heap. That's fairly straight-forward when the reference is static on inside another object. Harder when it is on the stack or a register, the jitter provides sufficient info to let the GC find it.
A reference variable is stored inline. If it's a local variable, it's allocated on the stack, if it's a member of a class it's allocated as part of the object on the heap.
An instance of a class is always allocated on the heap.
A reference is just a pointer, but what's special is that the garbage collector is aware of the reference. So, a reference uses the amount of space that a pointer uses. In a 32 bit process it uses 4 bytes, in a 64 bit process it uses 8 bytes.
The storage location of a local variable for the reference itself is platform dependent (jitters can choose where they want to store it.) Typically it will be in memory on the call stack for the method defining the local or in a CPU register. The size is also platform dependent, but is generally 4 bytes for 32-bit architecture and 8 bytes for 64-bit architecture.
The reference may or may not 'point' to the heap. It's better to think of it as an opaque reference identifier which can be used for accessing the object. The underlying pointer can change at runtime.
Regarding unused variables, the optimizing compiler will often eliminate any unused local variables entirely, so it has no impact at all on runtime performance. Also, the type of overhead you're talking about for storing a reference is miniscule for modern platforms.
If you need answers about this then I would recommend you get your hands on "CLR via C#", it is a book about how the CLR functions and it includes lots of information about this.
To answer your question, there are many things that you need to think about to answer this question.
For instance you need to store the instructions for each method in the class. When the class first loads this will effectively be a pointer to the .Net IL instructions. When the method is first needed by the application, it will be JIT compiled to actual instructions for the processor and this will be stored in memory.
Then you have static storage for class fields that will be stored only once per class.
Each class in .Net that is instantiated requires storage for various reasons, but not limited to things like inheritance, garbage collection, layout. Then you have storage for the various references that you may keep to the object which will itself take storage.
If memory is truly critical to what you are doing, then C# may not be the best choice for your application. Otherwise, just enjoy the benefits in productivity you will gain from using .NET and accept that this ease of use comes with a price of memory usage and less performance (in some cases) from a C/C++ app.