I'm building a home automation system with a web interface. It does a bunch of funtions so program memory and variable memory is at a premium. Html strings and other constant data are being stored in an external I2C EEPROM. Obviously it has an ethernet interface.
When I make a function call with "client" as an argument, the call consumes 60 bytes of program memory (according to the compiler) and probably some variable memory too. So generating a html page takes a lot of program memory simply in function calls.
void loop() {
Client client = server.available(); // see if data available
if (client) { // from ethernet
// do stuff //
printHtml(client,1); // ** This call takes 60 bytes
// more stuff //
printHtml(client,2); // ** This call takes 60 bytes
}
void printHtml(Client client, int n) {
// Get html string "n" from EEPROM
client.print(string);
}
the call to printHtml takes 60 bytes when client is an argument, and about 20 bytes when not. Since I have to make this call about 200 times, that's 8k of precious memory.
Does anybody know how I can keep the same program structure but reduce the memory used - for instance by making Client client global (tried that but does want to do it - I guess can't create the class until the ethernet code is started), or using pointers?
That's what I would have thought - however it's not the case (and I'm not doing any recursion). If I have 10 calls - I have a certain compiled program size. If I comment out any two of the calls, the program size goes down by 120 bytes.
I can only guess that void printHtml(Client client, int n) creates space for a whole new client structure and then copies client into it.
Sorry, my background is assembly and high level scripting - somehow missed the middle ground of C/C++ so I'm still learning.
Thinking a little more, the variable memory is probably reused, but new structures are created in program memory?? In assembly language we just wack everything on the stack during function calls, and one of these items could be a pointer to variable array in memory provided you know you're the only guy using it.
Thanks for your message. Yes aware of the basic difference between program flash memory and RAM memory. However static variables (e.g. fred = "this is my name") occupy both program flash as well as RAM variable memory. I know they can be restricted only to program flash using the PROGMEM directive, but that itself adds some overheads and complexity.
So to get back to the topic - how are variable structures used in arguments (including arrays, etc) mapped in program memory? The compiler tells me memory is being used.
I'd prefer to use pointers. etc but as explained am new to C/C++ and any assistance to modify the above code would eb appreciated.
I can only guess that void printHtml(Client client, int n) creates space for a whole new client structure and then copies client into it.
Sort of.
The way you are passing Client in your example is actually through a copy. The compiler generates a new class whenever you pass a class to a function like you are using the classes' copy constructor. That class takes space in the stack setup for your printHtml function that the compiler has to generate.
If you call the function multiple times as you show in your example, you get a new copy on the stack each time. (11: References & the Copy-Constructor). The increase in code size is the stack being prepared. I would think of it like passing each of the classes private variables to the function, one by one. in this case: (without the classes virtual tables being considered)
printHtml(uint16_t _srcport, _uint8_t sock, uint8_t *_ip, uint16_t _port, int n);
My test of your original, without string loading, is 36 bytes per call using the copy constructor, 10 bytes per call if client is passed by pointer. I can see that about 36 bytes is correct - about 28 of that is the copy constructor, 6 would be the stack setup.
If you change printHtml to :
void printHtml(Client *client, int n)
and call it like:
printHtml(&client,3);
then you get the 10 bytes per call. instead of the data being pushed on the stack, you are just pushing a pointer to the original class.
That's perfect - just the info I was looking for. Thanks. Being a previous assembly language guy I understand stacks, etc. but couldn't get my head around the pointer/classes thing and syntax. I'll give it a try this arvo.
Sweet (learning, learning, learning, always learning !!!) Thanks for all your help. I'm hoping to write a little article on my "arduino adventures" shortly.