interop memory allocation

J

John

I would like to ask a question that is obvious to all people porting
applications from the "traditional" C\VB6 interop scheme choosing C# vs
VB.NET.

We have a math library in C which ubiquitously takes a float* which
represents an array of floats. If the memory is allocated by the client,
in C# or VB.NET, I assume it must be "fixed" so that the GC does not
move the pointer during the C algorithm. Given that we are choosing
between C# and VB.NET, how is this done in either language? Is it even
possible in VB.NET. In terms of C#, I have heard that using the keyword
"fixed" is much faster then Marshal.AllocHGlobal. Is there a way to
offload this step into the C dll.

The question centers around these points:

1) Given a float* in the signature of a C dll is it required to fix that
pointer for the C function to be reliable when the memory is allocated
in managed code?

2) If (1) is true, is Marshal.AllocHGlobal the only way to do that in VB.NET

3) If (2) is there a way to offload that step to the C dll.

4) C# seems to lean more toward operating with interop easier, what
about this particular scenario?

I assumed that this question's answer would be easy to find using
google, but have not found this the case.

Thank you.
 
M

Marc Gravell

1) Given a float* in the signature of a C dll is it required to fix that
pointer for the C function to be reliable when the memory is allocated
in managed code?
Yes. You would probably get away with it a lot of the time, but to be
robust the buffer should be pinned (fixed) for the duration of the
call [but not forever].
2) If (1) is true, is Marshal.AllocHGlobal the only way to do that in VB.NET
Possibly; VB forums may know more...
3) If (2) is there a way to offload that step to the C dll.
Almost certainly not. And theoreticaly, even if there was, it could
conceivably be too late? (unlikely, though)
4) C# seems to lean more toward operating with interop easier, what
about this particular scenario?
Well, in C# you can use "fixed" etc, which seems fairly easy (although
it requires unsafe mode). However, VB has some other advantages re
late binding (Option Explicit Off), which can be useful in a few
scenarios, and is harder to do in C# - so you need to know what you
need to do. If you are working with pointers, then probably C#;
unpredictable/expando objects (kinda duck typing)? possibly VB. You
can mix and match, but you need an assembly per language.

Marc
 
W

Willy Denoyette [MVP]

John said:
I would like to ask a question that is obvious to all people porting
applications from the "traditional" C\VB6 interop scheme choosing C# vs
VB.NET.

We have a math library in C which ubiquitously takes a float* which
represents an array of floats. If the memory is allocated by the client,
in C# or VB.NET, I assume it must be "fixed" so that the GC does not move
the pointer during the C algorithm. Given that we are choosing between C#
and VB.NET, how is this done in either language? Is it even possible in
VB.NET. In terms of C#, I have heard that using the keyword "fixed" is
much faster then Marshal.AllocHGlobal. Is there a way to offload this step
into the C dll.

The question centers around these points:

1) Given a float* in the signature of a C dll is it required to fix that
pointer for the C function to be reliable when the memory is allocated in
managed code?
The array of floats will be pinned by the interop (PInvoke) layer for the
duration of the call, there is no need for you to pin explicitely.
2) If (1) is true, is Marshal.AllocHGlobal the only way to do that in
VB.NET

No, it's not, VB.NET uses the same PInvoke layer as all other managed
languages.
3) If (2) is there a way to offload that step to the C dll.

4) C# seems to lean more toward operating with interop easier, what about
this particular scenario?

No, no really , C# supports has some limited pointer support through the use
"unsafe" constructs, but there is seldom a need for this in interop
scenarios.


Willy.
 
M

Marc Gravell

The array of floats will be pinned by the interop (PInvoke) layer for the
duration of the call, there is no need for you to pin explicitely.

Sorry for adding confusion, then; my mistake.

Marc
 
A

Alvin Bruney [ASP.NET MVP]

What happens in the case of the Marshal.AllocHGlobal? Is the compiler or the
run-time smart enough to optimize it away or ignore the call or is that just
unnecessary overhead - performance implications?

--

Regards,
Alvin Bruney [MVP ASP.NET]

[Shameless Author plug]
The O.W.C. Black Book, 2nd Edition
Exclusively on www.lulu.com/owc $19.99
 
W

Willy Denoyette [MVP]

Alvin Bruney said:
What happens in the case of the Marshal.AllocHGlobal? Is the compiler or
the run-time smart enough to optimize it away or ignore the call or is
that just unnecessary overhead - performance implications?


Not sure what you mean ......

If you call a C function passing a float array as argument, you are relying
on PInvoke to marshal the managed array to native code.

[DllImport("gffg")]
extern static void Foo(float[] myFloats);

float[] fa = new foat[] {2.1, 6.0};
Foo(fa);
In above, CLR interop (PInvoke layer) will pin the array referenced by fa ,
take the address of the array and pass this address to the callee, when the
call returns PInvoke un-pins the fa object. The problem with this, is that
the object remains pinned for the duration of the call, which can negatively
impact the GC's performance.
Note that this is subject to JIT implementation details, for instance, in an
attempt to reduce the impact of pinning, the JIT 64 will pin the float[],
copy it's contents to an internal buffer, un-pin the float array before
passing the address of the internal buffer to unmanaged.

When using Marshal.AllocHGlobal, you are obviously marshaling the float
array yourself, so you must pass the pointer to the unmanaged buffer.

[DllImport("gffg")]
extern static void Foo(IntPtr myFloats);

IntPtr addressOfUnmanagedHeapBuffer =
Marshal.AllocHGlobal(sizeofFloatArray);
// copy floats to unmanaged addressOfUnmanagedHeapBuffer.
....
Foo(addressOfUnmanagedHeapBuffer );

Here you are marshaling the float[] to unmanaged and you pass the address of
the unmanaged array of floats to unmanaged. Obviously there is no need to
pin the float[] here.


Willy.
 

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