Re: Grr, garbage collector, don't move my arrays!
Quote:
Originally Posted by Mutant_Fruit
Really? Is that documented everywhere? It seems like a fairly serious limitation to have in a garbage collected language, especially one which prides itself on interop with unmanaged code.
If what you say is true, then all it would take to stop objects being collected would be a single pinned object in each generation. That's something which is pretty simple to do.
IT depends on where the pinned memory is allocated. Just think about it for a second. The way GG (Gen0) works is that all "valid" objects are moved up to the GEN1 heap, and then the GEN0 pointer is reset to the base (so that the memory can be allocated in a linear manner for future allocations on the GEN0 heap.
Now if an object on the GEN0 heap is pinned, it can not be moved to the GEN1 heap. This means that the GEN0 pointer can not be reset back (because it grows) it would trash the pinned object.
The alternative would be to keep track of what areas have to be "protected", but that would incur MAJOR overhead. One of the advaqntages of the GC memory model is that allocations are incredibly fast, so this would be REAL BAD.
The good news (because if there was no good news, pinning would be nearly fatal) is that the system has two alternatives:
1) An un-pinned object object may be freely moved. So the compiler can actually move the object OFF the normal heaps prior to pinning it. This typically happens, but does involve overhead.
2) The object can be originally allocated OFF the heap, which eliminates the original problem as well as the copy issue, but does add ovhead at the time where the object is unpinned.
Version 1.x had some real issues with these conditions,and you could usually get significant improvements by doing all of the memory management on the unmanaged side.
Version 2.0 has addressed most of these to produce optimal results, and the impact is rarely noticable. However the algorythms are not perfect. To prove this you can create a large number of big (but not large object heap eligible) objects, pass them to a distant part of the code (eg in another assembly), then loop through them performing pins (either via fixed or GCHandles that are created and destroyed). Fortunately this is a rather parasitic case....
Getting back to my original statement about using fixed... This typically keeps things very localized where there will be few (if any) new allocations occuring within the fixed block. If there are no allocations, there will be no GC. This allows additional optimizations.
My experience has been that while problems caused by ANY of the points I have mentioned are EXTREMELY rare, when they occur they can be a real pain. Having small local "fixed" statements I have NEVER seen the problem, and I am 100% that I have not pinned something for longer than necessary.
Regarding the need for the unsafe context, I find that it is usually necessary to have an unsafe context to accomplish the task that originally required me to pin the memory in the first place.
If I am developing an application which has significant interaction with unmanaged code that requires this type of pinning (especially the condition where a buffer must remain at one location across multiple calls), then the odds are greater than 99.55% that I will write that part of the system in mixed mode C++.
Re: Grr, garbage collector, don't move my arrays!
from what I've read, pinning doesn't keep the entire generation from being processed, only the pinned object, which results in fragmentation. If the entire gen was kept from being processed then fragmentation wouldn't be an issue.
Re: Grr, garbage collector, don't move my arrays!
The only documentation pinned objects states that a pinned object means the GC can't compact the pinned memory. This can lead to fragmentation. Nowhere does it say that a pinned object 'effectively stops GC'ing from happening'.
When using the async methods BeginSend and BeginReceive in sockets, the byte[] buffer you pass into the method gets pinned (indefinitely) until the unmanaged code has finished filling the buffer. I've written socket-heavy code and i never had issues where my memory usage ballooned out the window despite the fact i had dozens of pinned objects in each generation.
Re: Grr, garbage collector, don't move my arrays!
When you pass in a pointer to an array of datastructures created in the Managed Code to a DLL function in unmanaged code, what are the problems that are associated with traversing the array in the unmanaged code ?
Can you just move from one array index to another by just incrementing the pointer in the unmanaged code ?