Freeing resources used by a third party library

Hello,

I am building a system that reads once a day new parameters from a web server, using HTTP, and SIM800 library by Olivier Staquet.

The library uses a destructor, with this code:

/**
 * Destructor; cleanup the memory allocated by the driver
 */
SIM800L::~SIM800L() {
  free(internalBuffer);
  free(recvBuffer);
}

After reading the web server parameters, I want to make sure all resources generated by the "new" created object are destroyed, and memory released.

How to make sure this happens ?

My calling code (that is only the part that reads from server):

#include <SIM800L.h>

/********************************************************************************
 * Example of HTTPS GET with SoftwareSerial and Arduino-SIM800L-driver          *
 *                                                                              *
 * Author: Olivier Staquet                                                      *
 * Last version available on https://github.com/ostaquet/Arduino-SIM800L-driver *
 ********************************************************************************
 
 *******************************************************************************/
 /* Stripped down version GET removed
Using library SIM800L in folder: D:\AsusCloud\Electronica\Arduino\Development\libraries\SIM800L (legacy)
Using library SoftwareSerial at version 1.0 in folder: C:\Users\horac\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\libraries\SoftwareSerial 
"C:\\Users\\horac\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-size" -A "C:\\Users\\horac\\AppData\\Local\\Temp\\arduino\\sketches\\B24C07207DABA7577980D9D52EF9430B/HTTPS_GET_SoftSerial_testHbb_1_StrippedDown.ino.elf"
Sketch uses 12378 bytes (38%) of program storage space. Maximum is 32256 bytes.
Global variables use 530 bytes (25%) of dynamic memory, leaving 1518 bytes for local variables. Maximum is 2048 bytes.
*/

//HBB DELETE SEEMS TO DO NOTHING
// att remove delete and pointer study
#include <SoftwareSerial.h>

#define SIM800_RX_PIN 8
#define SIM800_TX_PIN 9
#define SIM800_RST_PIN 6

//const char APN[] = "datos.personal.com";
const char APN[] = "em";
const char URL[] = "http://nutritronix.com/selectV201W.php";
const char CONTENT_TYPE[] = "application/x-www-form-urlencoded";
const char PAYLOAD[] = "api_key=tPmAT5Ab3j7F9&device#=BC94";

SIM800L *sim800l;

void setup() {  
  Serial.begin(9600);   // Initialize Serial Monitor for debugging
  Serial.println(F("Start setup POST testHbb_1_strippedDown-01.ino")); //  while(!Serial); hbb what for ? 
                  //A-> just to wait in some AvrS serial init before executing
  SoftwareSerial* serial = new SoftwareSerial(SIM800_RX_PIN, SIM800_TX_PIN);// Initialize a SoftwareSerial
  serial->begin(9600);
  delay(1000);
  // Initialize SIM800L driver with an internal buffer of 200 bytes and a reception buffer of 512 bytes, debug disabled
  sim800l = new SIM800L((Stream *)serial, SIM800_RST_PIN, 200, 512);
  int hbb;
  hbb = (unsigned int)sim800l;
  Serial.print("sim800l (before): ");
  Serial.println(hbb, HEX);
  //delete sim800l;
  hbb = (unsigned int)sim800l;
  Serial.print("sim800l (after): ");
  Serial.println(hbb, HEX);
  
  // Equivalent line with the debug enabled on the Serial
  // sim800l = new SIM800L((Stream *)serial, SIM800_RST_PIN, 200, 512, (Stream *)&Serial);
  setupModule(); // Setup module for GPRS communication
}
 
void loop() {
 // Establish GPRS connectivity (5 trials)
  bool connected = false;
  for(uint8_t i = 0; i < 5 && !connected; i++) {
    delay(1000);
    connected = sim800l->connectGPRS();
  }
  // Check if connected, if not reset the module and setup the config again
  if(connected) {
    Serial.print(F("GPRS connected with IP "));
    Serial.println(sim800l->getIP());
    Serial.println(sim800l->getDES());
  } else {
    Serial.println(F("GPRS not connected !"));
    Serial.println(F("Reset the module."));
    sim800l->reset();
    setupModule();
    return;
  }

  Serial.println(F("Start HTTP POST..."));

// Do HTTP POST communication with 10s for the timeout (read and write)
  uint16_t rc = sim800l->doPost(URL, CONTENT_TYPE, PAYLOAD, 10000, 10000);
   if(rc == 200) {
    // Success, output the data received on the serial
    Serial.print(F("HTTP POST successful ("));
    Serial.print(sim800l->getDataSizeReceived());
    Serial.println(F(" bytes)"));
    Serial.print(F("Received : "));
    Serial.println(sim800l->getDataReceived());
  } else {
    // Failed...
    Serial.print(F("HTTP POST error "));
    Serial.println(rc);
  }
  delay(1000);

  // Close GPRS connectivity (5 trials)
  bool disconnected = sim800l->disconnectGPRS();
  for(uint8_t i = 0; i < 5 && !connected; i++) {
    delay(1000);
    disconnected = sim800l->disconnectGPRS();
  }
  
  if(disconnected) {
    Serial.println(F("GPRS disconnected !"));
  } else {
    Serial.println(F("GPRS still connected !"));
  }

  // Go into low power mode
  bool lowPowerMode = sim800l->setPowerMode(MINIMUM);
  if(lowPowerMode) {
    Serial.println(F("Module in low power mode"));
    sim800l='0';
  } else {
    Serial.println(F("Failed to switch module to low power mode"));
  }
  
}

void setupModule() {
  // Wait until the module is ready to accept AT commands
  //HBB
    Serial.print(F("Reseting SIM800L..."));
    sim800l->reset();
    delay(10000);
    Serial.print(F("End Reset SIM800L..."));


  while(!sim800l->isReady()) {
    Serial.println(F("Problem to initialize AT command, retry in 1 sec"));
    delay(1000);
  }
  Serial.println(F("Setup Complete!"));

  // Wait for the GSM signal
  uint8_t signal = sim800l->getSignal();
  while(signal <= 0) {
    delay(1000);
    signal = sim800l->getSignal();
  }
  Serial.print(F("Signal OK (strenght: "));
  Serial.print(signal);
  Serial.println(F(")"));
  delay(1000);

  // Wait for operator network registration (national or roaming network)
  NetworkRegistration network = sim800l->getRegistrationStatus();
  while(network != REGISTERED_HOME && network != REGISTERED_ROAMING) {
    delay(1000);
    network = sim800l->getRegistrationStatus();
  }
  Serial.println(F("Network registration OK"));
  delay(1000);

  // Setup APN for GPRS configuration
  bool success = sim800l->setupGPRS(APN);
  while(!success) {
    success = sim800l->setupGPRS(APN);
    delay(5000);
  }
  Serial.println(F("GPRS config OK"));
}

Thanks a lot !
Regards,
Horacio

The destructor gets called when the variable goes out of scope. If you want it to be destroyed then make the variable local to a single function that you call to use it.

But be forewarned that having freed these resources, if you use them and then the SIM800 code gets called you will crash. So even though you've freed them you should still keep them reserved which sort of defeats the purpose of freeing them.

Is there some particular other thing that you need to do that is memory intensive? You must make certain that the two cannot be in scope at the same time.

1 Like
delete sim800l;

Thanks for your time !

Delta_G,

I will try to work it in a special function, seems a good way.

Memory intensive: Yes, I do have a lot of stuff and need to be very cautious with memory, if not, it will not fit, and I will need more hard resources than a 328.

fgvalvo:

I tried

delete sim800l;

using that delete at the end of loop, to force in the next cycle the use of an undefined object, get a crash and be sure the SIM800L class object is destroyed.

But I am surprised, the loop continued to get good results from the server.
I am confused in the use of delete in this context.

When I test delete with VS Code with a sample Class it works as expected.

Thanks again, and have a very nice week end !
Horacio

That's just the caveat I was warning about earlier. I've seen too many people fall victim to this thinking.

Think of it like a carpool. You have four seats in the car and four people in the pool. You may think that it would be safe to add a fifth because usually one person is out on any given day and you can eliminate them from the seats. But one day all five people want to ride at the same time and you've got an issue.

If you don't keep memory reserved for the sim800, then you don't know the next time you need to use it if there will be memory for it. Remember that there's no garbage collection on an UNO. If you shoot the heap full of holes creating and destroying different sized objects then you just got less heap to work with until you got none.

What I'm driving at is that if you think this is going to be an issue then it is already time to upgrade the board before you've sunk a bunch of time and effort into something that may or may not work. That's just my 2 cents. But I've done lots of these kinds of projects and been in this same situation so many times. You always end up getting the bigger board in the end so go ahead and bite the bullet.

consequent usage of F-Makro might save some SRAM:

  Serial.print("sim800l (before): ");
  Serial.println(hbb, HEX);
  //delete sim800l;
  hbb = (unsigned int)sim800l;
  Serial.print("sim800l (after): ");

To be expected :slight_smile:

I'm not sure if the pointer to a deleted object is set to NULL. But you can force that yourself.

delete sim800l;
sim800l = nullptr;

And before you want to use it again, you check if sim800l points to an object or not

if(sim800l == nullptr)
{
  sim800l = new SIM800L((Stream *)serial, SIM800_RST_PIN, 200, 512);
}
if(sim800l == nullptr)
{
  // inform user
  Serial.println(F("Creating sim object failed"));
  // hang forever
  for(;;);
}

There are two if statements; the second one checks if the creating succeeded.

Instead of hanging forever, you can test every time that you want to do something with the object if it's a valid object.

E.g.

  bool connected = false;
  if(sim800l != nullptr)
  {
    for(uint8_t i = 0; i < 5 && !connected; i++)
    {
      delay(1000);
      connected = sim800l->connectGPRS();
    }
}

Note:
Creating the sim800l object in setup() is not needed if you want to free the resources and later recreate them again in loop().

Hello,

All answers are of great help, thanks so much!
I will try to get ATMega 4808, in 28 pin fmt, with SRAM going from 2k to 6k.
This Avr seems to be an easy upgrade. I don't know if this avr is available in Buenos Aires.
Will see tomorrow. If available, I can even keep my PCB layout, with little redesign.
And test all the soft possibilities you mention,
Thanks again!
Horacio

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.