VladL
VladL

Reputation: 13043

Prevent garbage collection for managed reference which is used in unmanaged code

My C# application uses wrapped C++ code for calculations.

C++ header:

__declspec(dllexport) void SetVolume(BYTE* data, unsigned int width);

C++/CLI wrapper:

void SetVolume(array<Byte>^ data, UInt32 width) 
{
    cli::pin_ptr<BYTE> pdata = &data[0];
    pal->SetVolume(pdata, width); 
}

C# :

public startCalc()
{
    byte[] voxelArr = File.ReadAllBytes("Filtered.rec");
    palw.SetVolume(voxelArr, 490);
    //GC.KeepAlive(voxelArr); makes no sense
}

The C++ SetVolume function starts asynchronous calculations. voxelArr is not referenced from the managed side any longer and is garbage collected.

How can I prevent the garbage collection for this reference until the unmanaged code finished it's work without to declare voxelArr as global variable? Creating a copy of array isn't an option as there is really a lot of data. Active wait inside of startCalc() isn't good too.

Upvotes: 10

Views: 4387

Answers (2)

HugoRune
HugoRune

Reputation: 13819

Another Alternative to your current approach:

Consider making the array global again, create and pin it once at the start, then reuse it whenever you need it. Objects as large as these should not be created on a whim, pool them. Only unpin and release it when you need to recreate it with a larger size

Storing the object in a global pool will prevent it from being garbage collected. You do not strictly speaking have to worry about pinning an object this large, but do so for consistency

Upvotes: 1

Reed Copsey
Reed Copsey

Reputation: 564691

You can use GCHandle.Alloc(voxelArr,GCHandleType.Pinned) to pin the array manually so the GC won't move or clean it.

You would then have to Free the handle when you knew the method was complete, which would require some form of callback for the completion.

Upvotes: 13

Related Questions