Vuo  0.5.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Modules

Description

When a node allocates memory on the heap and sends the pointer through an output port, the pointer travels to other nodes. The other nodes can hold onto that pointer for any amount of time. There's no guarantee of which node will be the last to use the pointer. Who owns that heap-allocated 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. The Vuo runtime uses reference counting to keep track of heap-allocated memory and deallocate it when all nodes are finished using it.

You need to use Vuo's reference-counting system to manage memory if:

Read on to learn how.

The reference-counting functions

Vuo provides three functions for reference-counting:

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 port type, read on to learn when to call these functions.

Automatically-inserted calls to the reference-counting functions

In many cases, the Vuo compiler automatically inserts calls to VuoRetain() and VuoRelease() where needed:

If the port type or instance data type is a pointer, the Vuo compiler calls VuoRetain() or VuoRelease() on the data itself. If the port type or instance data type is a struct, the Vuo compiler recursively traverses the struct and calls VuoRetain() or VuoRelease() on each field that is a pointer.

Managing memory for a port type

This section describes how to use reference-counting for port types that use heap-allocated data in various ways.

Port type is a heap-allocated type

If you're defining a port type that's a pointer to heap-allocated data, then your port type is responsible for registering that data. For example:

typedef char * MyString;
MyString MyString_valueFromJson(json_object * js)
{
const char *s = "";
if (json_object_get_type(js) == json_type_string)
*s = json_object_get_string(js);
MyString *m = strdup(s);
VuoRegister(m, free);
return m;
}

Port type is a struct containing a heap-allocated type

If you're defining a port type that's a struct, and the struct contains pointers to heap-allocated data, then your port type is responsible for registering that data. For example:

typedef struct {
float *elements;
size_t elementCount;
} ArrayOfFloats;
ArrayOfFloats ArrayOfFloats_valueFromJson(json_object * js)
{
ArrayOfFloats a;
a.elementCount = ...;
a.elements = (float *)calloc(elementCount, sizeof(float));
VuoRegister(a.elements, free);
...;
return a;
}

Port type is an opaque container for a heap-allocated type

If you're defining a port type that's some kind of container than a struct, and it contains pointers to heap-allocated data, then you have to do a little more work. Unlike a struct, the Vuo compiler can't analyze your container to automatically insert calls to VuoRetain() and VuoRelease(). Your port type is responsible for registering, retaining, and releasing the items in the container, as well as registering the container itself. For example:

typedef VuoText * PairOfStrings;
PairOfStrings PairOfStrings_valueFromJson(json_object * js)
{
PairOfStrings pair = (PairOfStrings)calloc(2, sizeof(VuoText));
VuoRegister(pair, PairOfStrings_destroy);
return pair;
}
void PairOfStrings_destroy(void *p)
{
PairOfStrings pair = (PairOfStrings)p;
VuoRelease(pair[0]);
VuoRelease(pair[1]);
free(pair);
}
void PairOfStrings_replaceFirst(PairOfStrings pair, VuoText newFirst)
{
VuoRetain(newFirst);
VuoRelease(pair[0]);
pair[0] = newFirst;
}

If instead of VuoText this container held a struct port type such as VuoSceneObject, then you would replace each call to VuoRetain() or VuoRelease() with a call to MyType_retain() or MyType_release(). In fact, you can call MyType_retain() or MyType_release() for any type. These functions are automatically generated by the Vuo compiler (though need to be declared in MyType.h). Depending on the underlying data type of MyType, they call VuoRetain() and VuoRelease() as needed.

Managing memory for node instance data

A stateful node class needs to register its instance data before returning it from nodeInstanceInit(). Use VuoRegister(), just like in the examples above for MyType_valueFromJson() in port types.

If the instance data is a container for heap-allocated items, then it needs to retain items that it stores and and release items that it no longer stores. Use VuoRetain() and VuoRelease(), just like in the example above for the opaque container port type.

Modules

 Reference-counting functions
 Functions to manage memory for heap-allocated port and node instance data.