Possible memory leak when component is overloaded
Summary
There are 3 components defined in the code below: sender, mapper, receiver. If the receiver is overloaded or processes the messages slower than they are generated by the sender, the memory consumption of the mapper starts to increase and it is not reduced even if there are no message to transmit/receive.
Steps and/or TTCN-3 code to reproduce
module MemoryUsage_InternalPorts {
type component MAIN_CT {}
type component PTC_CT {
port Internal_PT internal_PCO;
port Internal_PT incoming_PCO; // used only by the Mapper
port Internal_PT outgoing_PCO; // used only by the Mapper
}
type port Internal_PT message {
inout MSG
} with {extension "internal"}
type record MSG {
charstring addressx,
integer portx,
octetstring msg
}
const charstring c_messageBase := "Very important long message";
function f_sender() runs on PTC_CT {
var charstring vl_message := c_messageBase;
for(var integer i := 0; i < 10; i := i + 1) {
vl_message := vl_message & vl_message;
}
log("Message length: ", lengthof(vl_message));
var MSG vl_msg := { "whatever", 10000, char2oct(vl_message) }
for(var integer i := 0; i < 10*1000*1000; i := i + 1) {
internal_PCO.send(vl_msg);
}
log("====================================================================================================");
log("Sender component is done. Check the memory usage of the TITAN components, then press CTRL+c to stop.");
timer t_wait; t_wait.start(2147482.0); t_wait.timeout;
}
function f_receiver() runs on PTC_CT {
var MSG vl_msg;
var charstring vl_messageStr;
alt {
[] internal_PCO.receive(MSG:?) -> value vl_msg {
// some processing just to use CPU cycles
vl_messageStr := oct2char(vl_msg.msg);
for(var integer i := 0; i < lengthof(c_messageBase); i := i + 1) {
if(vl_messageStr[i] != c_messageBase[i]) {
log("oh, this is not good");
}
}
repeat;
}
}
}
function f_mapper() runs on PTC_CT {
var MSG vl_msg;
alt {
[] incoming_PCO.receive(MSG:?) -> value vl_msg {
outgoing_PCO.send(vl_msg);
repeat;
}
}
}
testcase tc_MemoryUsage_InternalPorts_SenderAndReceiver() runs on MAIN_CT {
var PTC_CT senderPTC := PTC_CT.create("Sender component");
var PTC_CT receiverPTC := PTC_CT.create("Receiver component");
connect(senderPTC:internal_PCO, receiverPTC:internal_PCO);
senderPTC.start(f_sender());
receiverPTC.start(f_receiver());
any component.done;
}
testcase tc_MemoryUsage_InternalPorts_SenderAndMapperAndReceiver() runs on MAIN_CT {
var PTC_CT senderPTC := PTC_CT.create("Sender component");
var PTC_CT mapperPTC := PTC_CT.create("Mapper component");
var PTC_CT receiverPTC := PTC_CT.create("Receiver component");
connect(senderPTC:internal_PCO, mapperPTC:incoming_PCO);
connect(mapperPTC:outgoing_PCO, receiverPTC:internal_PCO);
senderPTC.start(f_sender());
mapperPTC.start(f_mapper());
receiverPTC.start(f_receiver());
any component.done;
}
control {
execute(tc_MemoryUsage_InternalPorts_SenderAndMapperAndReceiver());
}
}
Recommended to use the following flags in the config file:
FileMask := ERROR | WARNING | PARALLEL | USER
ConsoleMask := ERROR | WARNING | USER
The memory usage is monitored by top
.
What is the current bug behavior?
When the CPU load is over 100%, the component (its process) starts to consume memory. Probably, the unsent/unprocessed messages start to pile up, however, the allocated memory never will be freed. It is not clear that this behavior is intentional or it is a bug.
What is the expected correct behavior?
Somehow free up the memory if it is not used anymore.
Titan version
8.2.0
Platform details (OS type and version)
Ubuntu 18 (but probably other platforms are also affected)
/cc @aknappqwt @mmagyari