Long story short, I have what I believe is a memory leak in my sketch that's causing the value in a variable to change after returning from a function call (variable is not used in the function). My sketch uses several different libraries and one particular function makes calls to at least one member function in each of the libraries. I want to experiment on various ways to declare the objects in my sketch to try and minimize RAM usage so I'm looking for feedback on the pro's and con's on different ways to declare objects. Here are some basic concept sketches of what I've come up with on different ways to use the objects:
First case is what I'm currently doing. Declaring the objects globally and making calls to the member functions from the main sketch. Applying my basic knowledge of OOP, I'm thinking this particular usage may be causing my problems.
The second case, declares the objects in Setup() and the ds() function and not globally. My understanding of how constructors/destructors work is once both Setup() and ds() go out of scope (at the ending } ) the destructors are called and the memory is freed up for use by other variables.
Now if my above assumptions are correct, would encasing the object declaration and corresponding member function call within it's own curly braces maximize the amount of free RAM since it frees up each instance after it's used?
This won't work, since the c1, c2, and c3 objects go out of scope when setup() ends and are undefined outside of setup. When you then try to reference them in ds(), you would cause all kinds of grief, but the compiler knows that you can't, because c1, c2, and c3 have scope that does not extend to ds().
{Class1 c1;c1.init();}
In this case, c1 goes out of scope even sooner. It's scope does not extend to ds().
{Class1 c1;c1.doSomething();}
Here you are creating a different instance called c1, and calling that instance's doSomething() method. This is not the same instance that was init()ed in setup().
PaulS:
Here you are creating a different instance called c1, and calling that instance's doSomething() method. This is not the same instance that was init()ed in setup().
Thanks PaulS. I actually don't mind if the new instance is different from the first instance (as long as they're not duplicated in memory that is). Let's say one of the library's is for a device like an accelerometer (which it is) and the .init() call configures the data registers in the accelerometer only. I don't care if the instance of the object is destroyed at the end of Setup() as it's only function is to configure the accelerometer. Now later on I create another instance to access features of the accelerometer (grab X,Y,Z crunch some numbers, etc..) and once again don't care that it gets destroyed when it goes out of scope.
I guess what I'm ultimately asking is (and in retrospect should have phrased it this way):
Is dynamically creating instances of objects similar to using local variables in functions? I know in a function when you declare a local variable, it is freed from memory once you return from the function call. Does the same apply to an instance of an object when it goes out of scope? Are there any pro's or con's (related to RAM usage) with the three examples above?
Is dynamically creating instances of objects similar to using local variables in functions?
Yes. The dynamically created objects go out of scope at the end of the block they are defined in, just like local variables. When they go out of scope, the desctructor is called, freeing the memory for other uses.
Are there any pro's or con's (related to RAM usage) with the three examples above?
Well, obviously the second example won't work, so you really only have two working examples. One uses global variables. The other uses local variables. If the objects don't need to persist information in the instance, then local variables will use less memory all the time. That's OK for some things, but not for others.
For the time the object exists, it uses the same amount of memory whether it is a local object, a static object, or a global object. Only its lifetime changes.
I have related questions. I'm running out of memory and I'm not sure where it is going. All 2K is being used somewhere, presumably in Ethernet header files because I'm declaring less than 200 bytes of variables. I did a serious rework to move a few hundred bytes from RAM to EEPROM and found that I actually lost RAM (other changes may be a cause, so still checking this). Is there documentation somewhere that says where the compiler puts stuff. For example, does the string in return "a string";get stored in RAM or in program memory ? Likewise, where is a const variable stored (and if not in program memory by default, why not?). Do structure definitions use RAM ?
struct example { // should not use RAM
int a;
char b[30];
};
example c; // uses RAM
Is there a way of getting a RAM allocation map from the compile process ?
String literals occupy both progmem and RAM - they are copied to RAM when the sketch starts. Struct definitions don't consume RAM. Take a look at the F macro - you can keep your strings in progmem only. Consider posting your code for more specific advice.
Thanks very much for the prompt reply. String literal (mis)handling is enough to explain my problem. I've heard of PROGMEM but not the 'F macro'... I'll hunt it down. I can probably sort things by moving more into EEPROM.
Copying string (const by definition) literals into RAM is really wasteful and cannot be needed if there is such a thing as the 'F macro': can this default behaviour be changed ?
For convenience, here is the reference to the macro... http://arduiniana.org/libraries/Flash/
I don't think anyone has actually answered your question yet, so here are my thoughts.
All three will work assuming you are not relying on the instance in consecutive calls to ds() being the same as each other or the same as the instance in setup()
Global objects: all memory is assigned on start-up and never freed.
Local function objects: memory for all three classes is assigned at the start of the method and freed at the end of the method.
Extra curly braces: this will assign the memory for each class and free it in turn.
If you want to see the order of things happening, I would add a constructor and destructor to each of your classes that outputs over the serial bus or something. The memory is assigned immediately before the constructor and freed immediately after the destructor.
The classes here are doing specific tasks in two different places, which is fine, but a waste of memory weather it be the stack or heap.
If the class definitions don't need to keep unique instance data then the class could be entirely static i.e.