Skip to content

Memory usage#

This section tries to give an overview why and how memory is being used in aes70 devices implemented using libaes70. It aims to help understand how much memory will be used by a device and what can be done to reduce memory usage when it becomes a problem.

In general memory is used in the following areas.

AES70 objects#

Each AES70 object will have a certain size. This can be broken down into the following items

Description Size Comments
vtable pointer sizeof(void*)
object number 4 Can be reduced using AES70_SHORT_OBJECT_NUMBERS.
device pointer sizeof(void*) Can be removed using AES70_OPTIMIZE_SINGLE_DEVICE.
each property change event sizeof(void*) Can be avoided using static methods to emit events.
implementation object ?

The implementation object will usually at least contain the role name (e.g. const char *) and either the property value itself (or an index - for instance - to identify the channel).

This means that without any additional tricks and taking advantage of the optimizations mentioned in the table one has to assume that each object will require 4 * sizeof(void*) bytes.

Without taking advantage of these optimizations and when using things like std::string the size can become much larger.

Devices#

Devices contain the object tree. This means that they usually store at least one pointer/reference for each object. Static devices can in principle be built by storing objects directly in place, which means that this can be further reduced. In static devices it is best to measure their size using sizeof to understand in detail how much memory they use.

The situation in dynamic devices is more complex:

  • Dynamic devices using aes70::dynamic_device::device will allocate each object using a shared_ptr which comes with a certain overhead depending on the implementation. Then, all objects will be store in a std::unordered_map by their object number. In addition to that, each aes70::dynamic_device::block will contain shared_ptr to each object in a std::vector. This means that the memory used will be at least 2 * sizeof(shared_ptr) + 4 per object stored in the device.

  • Dynamic devices using aes70::dynamic_device::linear_device will store objects in a global std::vector instead of using std::shared_ptr. This can reduce memory usage quite a bit, however at least 2 * sizeof(shared_ptr) per object.

In both situations it helps to take advantage of the reserve() methods in the device and block classes to pre-allocate sufficient capacity to store all object before adding them to the device. Still the above implementation does add overhead which cannot be avoided.

Connections#

Connections contain network receive and send buffers. Their size changes dynamically and depends on the use cases. On top of that, connections also store event subscriptions made by controllers. The size needed for these subscriptions can be significant and is important to understand when trying to reduce memory usage in a device.

Static devies#

Static devices assign each event inside of a device an index. Most objects will either emit property change events or no events. There are in principle objects which can have more than one event, but those are rare. Subscriptions are then stored in each connection based on the index. The size of each subscription depends on global configuration:

Configuration Size in bytes Comments
default 1/8 + 4
AES70_DISABLE_EV1 1/8 This will only work with controllers with EV2 support (aes70-2023).
AES70_ALLOW_ONLY_SIMPLE_SUBSCRIPTIONS 1/8 This might not work with some legacy controllers.

Dynamic Devices#

In dynamic devices, property change subscriptions will be stored seperately from other event suscriptions if they are simple subscriptions (made using the same OcaMethod or all-zero OcaMethod). Since in most devices the vast majority of events are property change events they make up the vast majority of memory usage. The size used by them depends on the configuration and dynamic device type used:

  • In aes70::dynamic_device::linear_device simple property change subscriptions will use 1/8 bytes each.
  • In aes70::dynaic_device::device simple property change subscriptions will use 4 + 1/8 bytes each. In addition there is some amount of overhead for the std::unordered_map used.

If non-simple subscriptions are supported, i.e. when AES70_ALLOW_ONLY_SIMPLE_SUBSCRIPTIONS and AES70_DISABLE_EV1 are both off, each non-simple subscriptions or subscriptions which are not property change events require:

  • Each EV1 subscription will use 12 bytes per event.
  • Each EV2 subscription will use 8 bytes per event.

In addition there will be some overhead for the std::unordered_set and std::unordered_map used.

Note

In summary, when memory usage neeeds to be reduced, it makes sense to enable AES70_ALLOW_ONLY_SIMPLE_SUBSCRIPTIONS. Alternatively, in situations in which the all supported controller applications are known and support EV2, AES70_DISABLE_EV1 can be enabled.