Vuo
0.4.7
|
When a node allocates data on the heap (for example, with malloc
) and sends it through an output port, the data travels to other nodes. The other nodes can hold onto that data for any amount of time. There's no guarantee of which node will be the last to use the data. Who owns that data? Who is responsible for deallocating it?
The answer is that the Vuo runtime takes ownership of the data as soon as it leaves the node, and is responsible for deallocating it. If you write a node class that allocates data on the heap, you just need to transfer ownership of the data to the Vuo runtime. Specifically, your node class needs to:
The Vuo runtime uses reference counting to keep track of heap-allocated memory and deallocate it when all nodes are finished using it. The Vuo API for node classes and types provides three functions for reference counting:
vuoRegister(void *, void(deallocate *)(void *))
informs the Vuo runtime that the data should be reference counted. This function should be called once for each heap-allocated data item that's sent through an output port or stored in node instance data. When the reference count of a data item is decremented to zero (its original value), the deallocate
function is called on the data item.vuoRetain(void *)
increments the data item's reference count, informing the Vuo runtime that someone has started using the data. The vuoRegister
function must be called on a data item before the first call to vuoRetain
.vuoRelease(void *)
decrements the data item's reference count, informing the Vuo runtime that someone has finished using the data. The vuoRetain
function must have been called at least N times on a data item before the Nth call to vuoRelease
.To make the reference-counting system easier for you to use, the Vuo compiler automatically inserts most of the necessary calls to vuoRegister
, vuoRetain
, and vuoRelease
. If you're implementing a stateless node class, you never need to call these functions. If you're implementing a stateful node class or a type, read on to learn when to call these functions.
If you define a type, and the type is a pointer to heap-allocated data, then the *_valueFromString
function is responsible for registering that data. For example:
(The *_stringFromValue
and *_summaryFromValue
functions should not register their return values.)
If your type is a struct, and some of its members are pointers to heap-allocated data, then the type definition is responsible for registering that data. For example:
For a struct type, you also need to declare the *_retain
and *_release
functions in order to use the type inside another container. The function implementations are generated automatically by the Vuo compiler, and they recursively traverse the struct and release all pointers to heap-allocated data. An example of declaring these functions:
If your type is some other container, and some of its elements are either pointers to heap-allocated data or structs containing pointers to heap-allocated data, then the type definitions is responsible for registering each element that's allocated, retaining each element that's added, and releasing each element that's removed — as well as registering the container itself. For example:
If the elements are structs containing pointers to heap-allocated data, use the *_retain
and *_release
functions to retain and release the struct values. For example:
If you use a node instance data type that already has a Vuo type definition (as described in the previous section), then you don't need to do anything. Memory management is already handled for you.
If you define a custom node instance data type within the node class, and the custom type consists of, or contains, pointers to heap-allocated data, then the node class is responsible for the same memory management as if you were defining a full-fledged Vuo type (as described in the previous section). The only difference is the function names (e.g. nodeInstanceInit
instead of *_valueFromString
).
For example, if the node instance data is a pointer to heap-allocated data, then the nodeInstanceInit
function is responsible for registering that data:
As another example, if the node instance data is a struct, and some of its members are pointers to heap-allocated data, then the node class is responsible for registering that data:
Except for the situations described above, the Vuo compiler automatically inserts calls to vuoRegister
, vuoRetain
, and vuoRelease
where needed. Specifically:
nodeInstanceInit
), its instance data is retained.nodeInstanceEvent
or nodeEvent
), for all output ports and instance data, the new data is retained and the old data is released.nodeInstanceFini
), its instance data is released.When a port or node instance data has a struct type, the Vuo compiler automatically inserts calls to vuoRetain
and vuoRelease
any members of the struct (and members of members of the struct, etc.) that are pointers.