Memory Management
This document describes what a user of the SIL Kit API has to be aware of regarding memory management.
Callbacks
When SIL Kit triggers a callback through an event handler such as e.g. EthernetController::AddFrameHandler()
, a user must not free or modify data provided through such an handler.
SIL Kit does own this data and deals with the needed memory management itself.
It is important to note that data provided in SIL Kit event handlers is only available during execution of the callback.
A user must not interact with such data after the execution of the callback since the corresponding memory may already be freed or reused by SIL Kit.
If data of an event handler is needed outside the scope of the callback, it must be copied. The memory management of the copied data is up to the user.
Handlers that are registered through an Add...Handler
call can be removed by a user through a corresponding Remove...Handler
call.
These Remove...Handler
calls are optional. SIL Kit removes these handlers during simulation shutdown itself.
Controllers
Controllers such as those created through e.g. CreateEthernetController
, do not have to be removed by a user manually.
These controllers are removed during simulation shutdown through SIL Kit itself.
Participant and ParticipantConfiguration
Participants and ParticipantConfigurations are created by users directly. They are provided through smart pointers. As soon as these pointers are not referenced any more, the corresponding entities will be cleaned up automatically by SIL Kit.
For the C API Participants have to be cleaned up by the user by calling SilKit_Participant_Destroy
.
ParticipantConfigurations are not modeled separately in the C API and therefore do not have to be considered in memory management.
SIL Kit Spans vs Vectors
SIL Kit provides payloads received through SIL Kit through a SilKit::Util::Span
instead of a regular vector.
This allows SIL Kit to provide access to these payloads without introducing an additional copy of these payloads.
Through avoiding these copies, SIL Kit’s performance is optimized.
To obtain a real copy of these payloads SilKit::Util::ToStdVector
can be used.
SIL Kit requires these SilKit::Util::Span
as well for sending payloads, e.g. in the CanFrame
that is provided to ICanController::SendFrame()
.
For converting byte vectors to these spans, SilKit::Util::ToSpan
or the SilKit::Util::Span
constructor can be used.
Examples
Within this section examples of how and how not to use the SIL Kit API regarding memory management are shown.
// do copy data provided in handlers into own structures when needed
std::vector<uint8_t> lastCanPayload;
canController->AddFrameHandler([&](ICanController* canController, const CanFrameEvent& frameEvent) {
lastCanPayload = SilKit::Util::ToStdVector(frameEvent.frame.dataField);
});
// don't access references to data received in handlers outside of the handlers
const CanFrameEvent* lastCanFrameEvent;
canController->AddFrameHandler([&](ICanController* canController, const CanFrameEvent& frameEvent) {
lastCanFrameEvent = &frameEvent;
});
//...
std::cout << "Frame Received:" << lastCanFrameEvent->frame << std::endl;
// don't free any memory/structure provided through SIL Kit manually
delete canController;
// don't modify data provided in handlers
canController->AddFrameHandler([&](ICanController* canController, const CanFrameEvent& frameEvent) {
frameEvent.frame.canId = 0;
});