Skip to content

Memory usage#

This section provides an overview of why and how memory is used in AES70 devices implemented using libaes70. It aims to help you 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 components:

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 contain at least 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 optimizations and taking advantage of the optimizations mentioned in the table above, one should assume that each object will require 4 * sizeof(void*) bytes.

Without taking advantage of these optimizations and when using data structures like std::string, the size can become significantly larger.

Devices#

Devices contain the object tree. This means that they usually store at least one pointer or reference for each object. Static devices can in principle be built by storing objects directly in place, which means that this overhead can be further reduced. For 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 stored in a std::unordered_map by their object number. In addition to that, each aes70::dynamic_device::block will contain a shared_ptr to each object in a std::vector. This means that the memory used will be at least 2 * sizeof(shared_ptr) + 4 bytes 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, it will still use 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 objects before adding them to the device. Still, the above implementation does add overhead that 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 devices#

Static devices assign each event inside a device an index. Most objects will either emit property change events or no events. There are, in principle, objects that 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 the 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 separately from other event subscriptions if they are simple subscriptions (made using the same OcaMethod or all-zero OcaMethod). In most devices the vast majority of events are property change events, and these make up the vast majority of memory usage. The size used by property change events 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::dynamic_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 disabled), each non-simple subscription or subscription that is not a property change event requires:

  • 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 needs to be reduced, it makes sense to enable AES70_ALLOW_ONLY_SIMPLE_SUBSCRIPTIONS. Alternatively, in situations where all supported controller applications are known and support EV2, AES70_DISABLE_EV1 can be enabled.