Documentation

Unity Engine


User Manual

Script Reference

Unity Engine


Pass data between managed and unmanaged code

Read time 2 minutesLast updated 13 days ago

When you're passing data between managed and unmanaged code, you need to consider how the data is stored and managed in memory. This topic explains how to pass data between managed and unmanaged code in Unity.
When you pass data between functions, parameters and return values can be copied to the stack or stored in the heap. The stack is typically used for value types, and the data persists for the duration of the function call. Data with a less predictable lifespan is stored on the heap. In C#, the scripting runtime manages the heap, which involves moving data and freeing memory that's no longer in use. In unmanaged code, you directly request and manage heap memory.
When you call an unmanaged function from managed code or a managed function from unmanaged code, both sides can directly access stack data. Therefore, you can pass small value types like
float
and
int
without extra precautions. You don't have to worry about the data disappearing before the other side of the call accesses it.
However, when you pass reference types and larger value types, such as strings, arrays, and some structs, the data might be stored on the heap. In this case, only a reference or pointer is passed between managed and unmanaged code. You must ensure that the data remains at the same memory location for as long as it might be accessed.
For the duration of a normal call into unmanaged code, the scripting runtime handles this for you. As part of marshalling, it keeps the relevant managed data alive and in place until the call returns. You only need to take extra measures for advanced scenarios where unmanaged code retains a reference to the data and accesses it after the call returns, such as an asynchronous callback or a pointer that the native code stores for later use. In those cases, you can use the
GCHandle
structure to "pin" an object in memory. The scripting runtime won't move or free a pinned object until you dispose of the
GCHandle
.
//Create a GCHandle to pin data in memory GCHandle handle = GCHandle.Alloc(yourObject, GCHandleType.Pinned); //... pass data to unmanaged code that retains it beyond the call ... handle.Free(); //Dispose of the handle when unmanaged code is finished
For examples of passing different types of data, refer to the following topics:

Topic

Description

Primitive typesHow to pass primitive value types like int, float, and char.
Structures, classes, and unionsHow to pass complex types.
NativeArraysHow to pass NativeArray objects.
StringsHow to pass string objects.