Reputation: 2886
I'm writing a program that invokes multiple C based functions (p/Invoke) in multiple threads.
From time to time, the program crashes with a access violation error. My first thought was that the GC optimized the memory and moved the chunk of memory, that the C function was working on, to a different location.
What I would like to do is have the GC working but disable the part where it moves (defrags) memory.
Is there a way to do this?
Upvotes: 2
Views: 307
Reputation: 659984
As other answers have said, the first thing to do is to ensure that you are pinning objects correctly. Assuming you have done that, what else can go wrong?
class C
{
public int handle;
...
~C() { InteropLibrary.DestroyHandle(handle); }
}
void M()
{
C c = GetSomeObjectUsefulInUnmanagedCode();
D d = InteropLibrary.UnmanagedMethodThatUsesHandle(c);
// COMMENT
d.DoSomethingWithStoredHandle();
}
What if a garbage collection happens at COMMENT
(*)? The garbage collector is free to say "hey, local variable c
is never referenced again in this method; I can be aggressive and treat it as dead!". If the finalizer runs and the handle is destroyed then when the last method runs, it accesses a destroyed handle and crashes.
To solve this rare but possible problem you can use GC.KeepAlive
to tell the garbage collector to be less aggressive about cleaning up a particular reference. If you keep c
alive until the end of the method then you know its destructor cannot possibly run.
(*) Of course the GC runs on a different thread, and can run at any time. The details of what operations are and are not interruptable by a GC are complicated and you shouldn't rely on those sorts of implementation details for correctness.
Upvotes: 5
Reputation: 5005
You can use the fixed
keyword in most cases.
From Eric Lippert's new blog it seems there are at least two other possibilities:
Note that in these two options require you to ensure the memory is correctly deallocated.
On a side note, if your problem is that a tiny bit of memory is moved around (causing access violations) then the solution is almost never to disable the entire moving-memory-around part.
Upvotes: 2
Reputation: 29213
I don't think you can do this globally, but you can use the fixed
keyword to pin specific objects, with the desired effect.
Upvotes: 1