I am building an application in Windows that can communicate with multiple serial devices. Sending and receiving data to a device is handled with the Win32 API and the GUI is handled by GTK3. A worker thread is created by g_thread_new
to run the device polling loop and the text view/buffer is updated by using g_timeout_add
. When the device is streaming, its output is in ASCII text which is then inserted into a buffer if it is determined that there is a new line that has not yet been inserted. The polling loop runs infinitely until a disconnection function is triggered which then cleans up the resources.
I have discovered a memory leak that I believe to be somewhere within the buffer update function. When this function is commented out (i.e. nothing gets inserted into the buffer), I no longer have a leak.
gboolean
updateViewport (gpointer data) {
SerialDevice *device = (SerialDevice *) data;
device = getDeviceById (device->id);
if (device != NULL) {
if (device->dataStringBuffer[device->lineCount - 1] != NULL && device->newDataForDisplay == PENDING) {
GtkTextMark *mark;
GtkTextIter start, end;
mark = gtk_text_buffer_get_insert ( device->viewPort->textViewBuffer);
gtk_text_buffer_get_iter_at_mark ( device->viewPort->textViewBuffer, &iter, mark );
gtk_text_buffer_get_bounds ( device->viewPort->textViewBuffer, &start, &end );
gtk_text_buffer_get_iter_at_offset (device->viewPort->textViewBuffer, &iter, -1);
if (device->viewPort->linesDisplayingInBuffer > lineLimit) {
gtk_text_buffer_delete(device->viewPort->textViewBuffer, &start, &end);
device->viewPort->linesDisplayingInBuffer = 0;
}
gtk_text_buffer_insert (device->viewPort->textViewBuffer, &iter, device->dataStringBuffer[device->lineCount - 1], -1);
device->newDataForDisplay = EMPTY;
device->viewPort->linesDisplayingInBuffer++;
gtk_text_buffer_delete_mark(device->viewPort->textViewBuffer, mark);
}
}
return G_SOURCE_CONTINUE;
}
For now, I want to limit the total number of lines that the user can scroll through. When the limit is reached, I am using the gtk_text_buffer_delete
method to clear out the buffer. I am calling gtk_text_buffer_delete_mark
to release the reference to the mark I created.
Incoming data read into incomingBuffer
is copied into dataStringBuffer
, an array of strings which is then inserted into the text view buffer. The memory for dataStringBuffer
is allocated on device creation and released when the device is disconnected.
if (bitsRead > 1) {
// Reset lineCount to overwrite the lines that have already been displayed
if (device->lineCount == DATA_STRING_BUFFER_SIZE - 1) {
device->lineCount = 0;
}
g_strlcpy(device->dataStringBuffer[device->lineCount], device->incomingBuffer, INCOMING_BUFFER_SIZE);
device->lineCount++;
device->newDataForDisplay = PENDING;
PurgeComm(device->hSerialComm, PURGE_RXCLEAR);
memset(device->incomingBuffer, 0, INCOMING_BUFFER_SIZE);
}
Memory consumption is small when only a single device is streaming to a buffer, however this is not the norm. There will typically be 6 to 8 devices streaming at the same time, each on their own worker thread, which magnifies the impact of the leak. My hunch is that references are not being released when I am calling gtk_text_buffer_delete
to delete the lines out of the buffer, however I’m new the mechanics GTK library.
Any advice/criticism/feedback is more than welcome.