For the first question:
There is 2kB of SRAM. There is an additional 32bytes of CPU registers, and a further 64bytes of I/O registers (things like the PORTA/DDRA/etc. registers).
Add these all up we get 2048+32+64 = 2144bytes of addressable memory. Convert that to hexadecimal you get 0x860 - or in address terms 0x000 to 0x85F.
The SRAM memory itself is the 2kB block from 0x060 to 0x85F.
For the second question:
malloc
uses a so called "freelist" which maintains which chunks of memory are available to allocate or reallocated. This list is stored in the same SRAM as the memory you are allocating, and is updated on the fly as you use allocate memory.
Each entry in the freelist is a 16bit pointer, which points to the next entry forming a chain - each entry keeps track of where the next entry is - and a 16bit size which says how big the current block is.
As a result, each block of memory allocated using malloc
must be at least 4 bytes in size in order to store the list entry. When you request a single byte of memory, it has to round that up to 4 bytes so that when that memory is deallocated, there is room for a list entry to be stored there.
Rather than go into exact details, the freelist approach is explained in the avr-libc documentation here. The following quote explains the need
The freelist itself is not maintained as a separate data structure, but rather by modifying the contents of the freed memory to contain pointers chaining the pieces together. That way, no additional memory is reqired to maintain this list except for a variable that keeps track of the lowest memory segment available for reallocation. Since both, a chain pointer and the size of the chunk need to be recorded in each chunk, the minimum chunk size on the freelist is four bytes
If you can't get your head around it (the process is not immediately obvious), you need not worry. The simple thing to remember is that each chunk you malloc
will be at least 4 bytes in size, even if you only want 1.
Also worth noting after a bit of experimentation, the amount of memory allocated appears to always be the larger of either 4 bytes, or the requested amount + 2bytes. For example if you ask for 3 bytes, then 5 bytes will be allocated. If you ask for 8 bytes you will get 10.
As to why the extra 2 bytes are allocated, I am unsure. I cannot find reference to this in the avr-libc documentation.