Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak when using sqlite3 with C++

The program writes into SQLite database, the messages are received through a wireless module. But somehow there is a memory leak every time a message is received and written to the database, after about 10 000 writes the program is using 1GB of memory.

The documentation for SQLite3 with C++ says that memory leaks are prevented with sqlite3_finalize() and sqlite3_close() which are present:

#include <iostream>
#include <string>
#include <sstream>
#include "sqlite3.h"

using namespace std;

#define DB "test.db"
sqlite3 *dbfile;

bool connectDB();
void disonnectDB();
int insOrUpdate(string s);
int select(string s);

struct messageStruct_t {
  float value;
};

bool isOpenDB = false;

int main() {
  int counter = 0;
  while (1) {
    int header = 1;
    int message = rand() % 3;

    if (message) {
      counter ++;

      switch (header) {

      case 1: {
        messageStruct_t recMessage;
        recMessage.value = 55;
        int receivedSendersID = 2;

        //SQL query to get foreign key
        stringstream strm_select;
        strm_select << "SELECT id FROM table1 WHERE sendersID="
                    << receivedSendersID;
        string s_select = strm_select.str();
        cout << "SQL query: " << s_select << endl;
        int sendersID = select(s_select);
        cout << "Sender's ID: " << sendersID << endl;


        if (sendersID == 0) {
          cout << "Error: Sender doesn't exist\n";
        } else {
          stringstream strm_insert;
          strm_insert << "INSERT into table2(id,value,sender_id) values("
                      << counter << ", "
                      << recMessage.value << ", " << sendersID << ")";
          string s_insert = strm_insert.str();
          cout << "SQL query: " << s_insert << endl;
          insOrUpdate(s_insert);
          cout << "Recorded data: " << recMessage.value << endl;
        }
      }

      default: {
        break;
      }

      }
    }
  }
}

bool connectDB () {
  if (sqlite3_open(DB, &dbfile) == SQLITE_OK) {
    isOpenDB = true;
    return true;
  }
  return false;
}

void disonnectDB () {
  if ( isOpenDB == true ) {
    sqlite3_close(dbfile);
  }
}

int insOrUpdate(string s) {
  if (!connectDB()) {
    return 0;
  }

  char *str = &s[0];
  sqlite3_stmt *statement;
  int result;
  const char *query = str;

  if (sqlite3_prepare(dbfile, query, -1, &statement, 0) == SQLITE_OK) {
    result = sqlite3_step(statement);
    //the documentation says that this destroys the statement and prevents memory leaks
    sqlite3_finalize(statement);
    return result;
  }
  //and this destroys the db object and prevents memory leaks
  disonnectDB();
  return 0;
}

int select(string s) {
  if (!connectDB()) {
    return 0;
  }

  char *str = &s[0];
  sqlite3_stmt *statement;
  const char *query = str;
  string returned;
  if (sqlite3_prepare(dbfile, query, -1, &statement, 0) == SQLITE_OK) {
    int ctotal = sqlite3_column_count(statement);
    int res = 0;

    while (1) {
      res = sqlite3_step(statement);
      if (res == SQLITE_ROW) {
        for (int i = 0; i < ctotal; i++) {
          string s = (char*)sqlite3_column_text(statement, i);
          cout << s << " ";
          returned = s;
        }
        cout << endl;
      }
      if (res == SQLITE_DONE || res == SQLITE_ERROR) {
        cout << "done " << endl;
        break;
      }
    }
  } else {
    cout << "Can't prepare" << endl;
    return 0;
  }
  sqlite3_finalize(statement);
  disonnectDB();

  int result;
  stringstream convert(returned);
  if (!(convert >> result)) {
    result = 0;
  }

  return result;
}

CREATE TABLE table1 (
id INTEGER NOT NULL,
sendersID INTEGER,
PRIMARY KEY (id)
);
CREATE TABLE table2 (
id INTEGER NOT NULL,
value FLOAT,
sender_id INTEGER,
FOREIGN KEY(sender_id) REFERENCES table1 (id)
);

INSERT INTO table1(sendersID) values(2);
like image 415
Vasil Kalchev Avatar asked Oct 16 '25 10:10

Vasil Kalchev


1 Answers

In your connectDB(..) call , you don't check if the database is already open before opening it again. Your memory leak is probably from the repeated mappings of this database into your memory space.

There may be other issues with this program but the change below to connectDB(..) should help with the leak on every successful insert.

bool connectDB() {
    if (false == isOpenDB && sqlite3_open(DB, &dbfile) == SQLITE_OK) {
        isOpenDB = true;
    }
    return isOpenDB;
}
like image 145
JimmyNJ Avatar answered Oct 19 '25 01:10

JimmyNJ



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!