Where does 93 bytes of RAM go?

Using this sketch, for a Uno, on IDE 1.0.5:

volatile byte foo;

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  
  Serial.print (F("foo = "));
  Serial.println ((int) &foo);
  }  // end of setup

void loop () { }

I get the output:

foo = 272

I take that to mean that foo starts at address 272. Presuming that it is the last allocated variable, it would appear therefore that there are 272 bytes of RAM in use already. Now I can account for some of them:

  • 34 bytes for the HardwareSerial instance (Serial)
  • 64 bytes for the Serial transmit buffer
  • 64 bytes for the Serial receive buffer
  • 4 bytes for the Serial transmit buffer head and tail pointers
  • 4 bytes for the Serial receive buffer head and tail pointers
  • 9 bytes for keeping track of millis / micros

That adds up to: (34 + 64 + 64 + 4 + 4 + 9) = 179

So, where do the last 272 - 179 = 93 bytes go? What are they used for?

I ask because with only 2048 bytes of RAM, losing 93 would seem to be a misfortune.

Using 1.5.7 & compiled for uno I get 189 bytes, still ten over though.

6 bytes are reserved for dynamic memory.

[quote author=what uses ram]00800100 00000002 D __malloc_heap_end
00800102 00000002 D __malloc_heap_start
00800104 00000002 D __malloc_margin
00800106 00000010 V _ZTV14HardwareSerial
00800116 B __bss_start
00800116 D __data_end
00800116 D _edata
00800116 00000001 B foo
00800117 0000009d B Serial
008001b4 00000001 b timer0_fract
008001b5 00000004 B timer0_millis
008001b9 00000004 B timer0_overflow_count[/quote]

EDIT: The length of serial is different also, which probably accounts for the 10 extra bytes.
Whatever the overhead was, it must have been resolved.

I knew I had forgotten something: RAM starts at 0x100 because the first 256 bytes are used to address hardware registers.

So:

00800100 00000002 D __malloc_heap_end
00800102 00000002 D __malloc_heap_start
00800104 00000002 D __malloc_margin
00800106 00000010 V _ZTV14HardwareSerial
00800116 B __bss_start
00800116 D __data_end
00800116 D _edata
00800116 00000001 B foo

foo is at 0x116 (278) which is therefore 0x16 bytes from the start of RAM.

Hmm. More investigation required.

Or does RAM end at 0x80FF? So we still have 32 kB of RAM?

00800100 00000002 D __malloc_heap_end
00800102 00000002 D __malloc_heap_start
00800104 00000002 D __malloc_margin
00800106 00000010 V _ZTV14HardwareSerial <--- whatever this is!
00800116 B __bss_start
00800116 D __data_end
00800116 D _edata

I read that as adding on another 22 bytes. So we still have 93 - 22 = 71 to go.

RAM ends at 0x8FF and starts at 0x100 so there is 2048 bytes. If foo=272 -> 0x110, it si 17. byte in order from the beginning.

The 800 prefix in "nm" output and .hex files is the gcc way to keep ram and flash address spaces separate.

I read that as adding on another 22 bytes. So we still have 93 - 22 = 71 to go.

Everything seems accounted for:

malloc 6
hardware serial 16
foo 1
Serial 157
millis 9
total 189

The same size as what the IDE stated.

OK, it seems "foo" isn't at the end of RAM. Try this sketch:

#include "memdebug.h"

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  Serial.print (F("Free memory = "));
  Serial.println (getFreeMemory ());
  }  // end of setup

void loop () { }

Output:

Free memory = 1702

So 2048 - 1702 is 346.

Allowing for the 179 I had before, plus your malloc (6) and HardwareSerial (16) there are still quite a few bytes (145) unaccounted for.

memdebug.c (2.8 KB)

memdebug.h (694 Bytes)

Are you accounting for what init() does? Does it use SRAM?

Mmm how about the the stack pointer, and when you are in setup() the space used by the call to setup on the stack.

Mark

A look at the IDE generated main.cpp (or is it .c) may show something. Any local vars there will be on the stack for the life time of the sketch.

Mark

For an array you store the address of the array as well as the data.

Mark

PaulS:
Are you accounting for what init() does? Does it use SRAM?

You tell me.

I can allow 4 bytes for the initial code calling main and main calling loop, but after that I can't say.

PaulS:
Are you accounting for what init() does? Does it use SRAM?

init() does not have any static declarations, nor does it use malloc or new.

holmes4:
A look at the IDE generated main.cpp (or is it .c) may show something. Any local vars there will be on the stack for the life time of the sketch.

Mark

#include <Arduino.h>

int main(void)
{
	init();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

No local variables.

holmes4:
Mmm how about the the stack pointer, and when you are in setup() the space used by the call to setup on the stack.

Mark

2 bytes maybe.

No local variables.

But there are global variables - serialEventRun and the pointer to the serialEvent() function, for two.

That's one isn't it? The variable serialEventRun.

OK, that's another two bytes.