Re: Garbage collectable pinned arrays!
- From: "Willy Denoyette [MVP]" <willy.denoyette@xxxxxxxxxx>
- Date: Wed, 13 Feb 2008 12:34:25 +0100
"Ben Voigt [C++ MVP]" <rbv@xxxxxxxxxxxxx> wrote in message news:%23TKXqVdbIHA.1960@xxxxxxxxxxxxxxxxxxxxxxx
Willy Denoyette [MVP] wrote:"Ben Voigt [C++ MVP]" <rbv@xxxxxxxxxxxxx> wrote in message
news:%23bjU84abIHA.5400@xxxxxxxxxxxxxxxxxxxxxxx
This is not what pinned means in this context. The objects on the
LOH (all version of the CLR) are at a fixed address for their life
time, but that doesn't mean they are pinned. Pinning is an explicit
action
Ok, but then they don't require pinning. In any case they
inherently have the fixed address which requires pinning to obtain
for normal objects.
As I said before, pinning is an action performed by the Interop layer
*when the GC initiates a scan, and it's not done by means of a call to
GCHandle.Alloc. You only need to pin "explicitely" when you are
passing an object to unmanaged code and you need to keep the object
alive and at fixed location after the PInvoke call returned, during
the call the PInvoke layer takes care of eventual pinning.
That's not an unusual case. I've already given two examples of APIs in widespread use which require a buffer to stay in one position after the initial function call which accepts the pointer.
True, but if you need this, why is the cost of pinning so important?
The cost of GCHandle.Alloc is ~5500 cycles. That means a one time cost to pin a buffer that lives until the end of the process, if you do this early in the process you won't suffer from fragmentation of the gen0 heap as this object will end on the gen2 heap anyway.
Also, you keep ignoring my remark that the fact that addresses of
*Large* objects are fixed is a convenience of the current version of
the CLR, nothing stops MS from changing this.
Which is why the OP is asking for a keyword / MSIL flag that will let the runtime know that the object is intended to be fixed for as long as it lives. It would be an implementation detail whether the memory is allocated from the LOH, OLE task allocator, etc, etc. Also I don't think that sacrificing GC for such objects would necessarily be a big loss, they either will live to the end of the process anyway, or they can be explicitly freed.
But , this is what "fixed" is meant for, sure, it's scope is limited by it's containing function scope, but you can perfectly pin an object across several unmanaged function calls.
Consider following code snip:
...
internal class C
{
internal int v;
internal long l;
internal byte[] ba;
public C()
{
l = 123456789;
ba = new byte[2000];
}
}
void Foo()
{
int[] ia = new int[100];
C c = new C();
c.ba[0] = 123;
int x = 0;
unsafe
{
fixed (int* ptri = ia) // ptri becomes a "an untracked pinned byref local"
fixed (int* ptrv = &c.v) // ptrv becomes a "an untracked pinned byref local"
fixed (byte* ptrba = c.ba) // ptrba becomes a "an untracked pinned byref local"
{
//call unmanaged code passing the pointers as arguments...
...
} // end of fixed scope, "release" the pinned references
}
}
The JIT compiler fills the "pointer table", which is part of the GCInfo table, with references to objects that cannot get moved when the GC comes along.
In above sample that means that :
- the instance of the int[] pointed to by ia,
- the instance of an int pointed to by c.v, and
- the instace of the byte[] pointed to by c.ba cannot move.
Note that fixing c.v also fixes the location of c instance.
This way of "fixing" objects in C# comes at nearly no costs.
If this doesn't suits your needs, then you will have to use the Marshal class or GCHandle.Alloc, carefully considering it's (fixed) costs. If these costs are too high, then you have choosen the wrong tool for the job at hand I'm afraid.
Hence my suggestion of T[] Marshal.AllocCoTaskMem<T>(int elementCount), T required to be a "reference free" value type, meaning all members are "reference free" value types.
Why not post your suggestion(s) to the connect site? It makes little sense to post them here, I guess.
It would be useful to request that a particular buffer not be
subject to relocation by the GC. Probably the easiest way to do
this would be to place it in the LOH. The OLE task allocator or
HGlobal allocator, both of which are already exposed by the Marshal
class in a typeless way, would be other options. It could be as
simple as adding a T[] Marshal.AllocCoTaskMem<T>(int elementCount)
override.
But now you are allocating from the unmanaged heap (COM heap or CRT
heap or whatever). So now you will incur the costs of copying back
and forth, again this depends on the semantics, but might be a
solution when you need to pass large data chunks to unmanaged land.
Why? .NET could create a proper array descriptor storing the
metadata alongside and access it directly.
Where? outside of the GC heap? Who's going to "manage" these objects
then? As you may know, there are other cheap means to pass fixed
buffers to managed code.
The CLR has no trouble with data outside the GC heap, it just can't hold references to objects inside the GC heap (because then objects could be reachable but the GC wouldn't know that). For example, MSIL instructions have no trouble accessing structures on the stack.
I have no idea what can/cannot be done, only the CLR team can answer such questions, after all, they are the only ones that will have to implement such changes, arent't they?
Willy.
.
- Follow-Ups:
- Re: Garbage collectable pinned arrays!
- From: Ben Voigt [C++ MVP]
- Re: Garbage collectable pinned arrays!
- References:
- Re: Garbage collectable pinned arrays!
- From: Jesse McGrew
- Re: Garbage collectable pinned arrays!
- From: Atmapuri
- Re: Garbage collectable pinned arrays!
- From: Willy Denoyette [MVP]
- Re: Garbage collectable pinned arrays!
- From: Ben Voigt [C++ MVP]
- Re: Garbage collectable pinned arrays!
- From: Willy Denoyette [MVP]
- Re: Garbage collectable pinned arrays!
- From: Ben Voigt [C++ MVP]
- Re: Garbage collectable pinned arrays!
- From: Willy Denoyette [MVP]
- Re: Garbage collectable pinned arrays!
- From: Ben Voigt [C++ MVP]
- Re: Garbage collectable pinned arrays!
- Prev by Date: Re: XmlSerializer again
- Next by Date: Re: String#LastIndexOf
- Previous by thread: Re: Garbage collectable pinned arrays!
- Next by thread: Re: Garbage collectable pinned arrays!
- Index(es):
Relevant Pages
|