user27779: When compiling a sketch, after linking, the build outputs a kind of forecast on RAM usage, e.g.:

Minimum Memory Usage: 1456 bytes (71% of a 2048 byte maximum)

Is it possible to somehow get a breakdown or itemization of these 1456 bytes and details on exactly where in my code, or in included libraries, they are used? 

user23325: This was a great question and helped me recently as I'm building quite an extensive Arduino app using a Nano (ATMega328 and 32K of program memory).
At one point I was almost out of program memory and I was a bit shocked.
I didn't think the code was that large.
My Tests and Results
With the comments I read through the posts on this answer I decided to build a blank app and examine the results as I added libraries etc.  Here are my results (Using Arduino IDE 1.8.13):

 blank sketch takes up 444 bytes of program storage space (max is 30720 bytes).

Sketch which includes 6 libraries✔ uses up 6218 bytes
<LiquidCrystal_I2C.h>, <Wire.h>,<ds3231.h>,<SD.h>,<EEPROM.h>,<SoftwareSerial.h>

adding one line Serial.begin(9600); uses 6324 bytes NOTE: 6324 - 6218 = 106 bytes even though I only added 19 bytes (the characters for that line).

Adding on more line Serial.print("a"); results in 6342 bytes used. That's 18 more bytes (6324 - 6342 = 18) which is the exact number of characters I added with that line (including semicolon).

Adding a 2nd line with Serial.print("a"); results in 6358 (16 bytes)

Adding a 3rd line of Serial.print("a"); results in 6374 (16 additional bytes).


I hope this helps a bit. I'm going back to my app now and removing all the Serial lines I used for debug output.  They're just eating up program memory now.
Actually, I'll probably even use the conditional compilation (shown in this SO answer) so I can still print when in debug.
 Blank sketch means one with only the void setup() {} void loop() {} structures and nothing else.
✔ These are the libraries which I am using in my project.
 I came back and added these additional lines with the amount of Program Memory used because there was a comment that lines of code do not impact memory at all. Of course they do.  At some point all Program Memory is used up and your program will no longer fit into flash.  This is what I was having a challenge with as my extensive program (which includes sensors, LCD, sd card, and bluetooth) continues to grow.

user3917: Looking at an assembly listing of your code is the most direct method for finding out details of space allocation.  On my Ubuntu Linux system, I use a shell script (that is, a file containing shell commands) like the following to produce an assembly listing of the most-recently-compiled .ino file, which must be in the working directory when the script executes:
#!/bin/sh
# Look for .ino in current directory, and find recent /tmp/build...
item=*.ino
[ -z "$item" ] && echo ino file not found && exit
BDIR=/tmp/$(ls -t /tmp | egrep -m1 build.*tmp)
BASE=$(basename $item .ino)
avr-objdump -S -I$PWD $BDIR/$BASE.cpp.elf > $BASE.ino.asm

All the stuff before the avr-objdump line allows the script to find out the name of the current .ino file and the name of the /tmp/ subdirectory where the .ino's .elf file is found.
You can also use avr-objdump to get a more concise size listing, as follows, where $BDIR and $BASE are as in the script above and represent the build directory in /tmp/, and the basename of the .ino file.
avr-objdump -C -d $BDIR/$BASE.cpp.o| egrep -C2 '^Disassembly' | egrep -v '^--|^$|^Disassembly' | less

This will produce a list with two-line entries like the following, in which each line beginning with 00000000 is a subroutine name, and the next line shows the last line of its compiled code.  In this example output, the setup_PowerDown() routine has 0xA4 bytes of code, ISR __vector_13 has 0xC6 bytes, keepAlive() has 0x10 bytes, etc.
00000000 <setup_PowerDown()>:
  a4:   08 95           ret
00000000 <__vector_13>:
  c6:   18 95           reti
00000000 <keepAlive()>:
  10:   08 95           ret
00000000 <eeWrite1(unsigned char, unsigned char)>:
  3a:   08 95           ret
00000000 <eeWrite2(unsigned char, unsigned char)>:
  18:   0c 94 00 00     jmp     0       ; 0x0 <eeWrite2(unsigned char, unsigned char)>
00000000 <parValidate(unsigned char, unsigned char, unsigned char)>:
  64:   08 95           ret
00000000 <loadSettings()>:
  e0:   08 95           ret
00000000 <applySettings()>:
  84:   08 95           ret

Some IDEs provide symbol table information that includes sizes of routines, stack frames, and data.  I don't know if that's available via Arduino IDE, AVR-libc, or GNU Binutils.  The symbol table provided by avr-readelf -s (as in following command) provides quite detailed symbol information that seems quite useless in its raw form.
avr-readelf  -s  $BDIR/$BASE.cpp.o

The methods described above are somewhat ad hoc, and depend on files left after avr-gcc or avr-g++ run.  I don't know of any “official” methods for getting the information you want to see. 

user4143: You can automatically generate a "map" file every time you compile. This gives you a full breakdown of how everything is linked together by the linker, including the size of each section and other useful debugging information.
A simple modification to platforms.txt in hardware/arduino/avr is all that is needed.  Find the line starting compiler.c.elf.flags= and add to the end of it:
 -Wl,-Map,"{build.path}/{build.project_name}.map"

If you like you can replace {build.path} with a hard-coded path, such as your desktop, and the .map with .txt to allow it to easily be opened by notepad or whatever you use (assuming Windows, of course).

user7508: Since you seem interested about RAM, rather than flash usage, I suggest
you look at the symbol table of your compiled program, which will be
more telling than the disassembly. On my Linux system, I usually do the
following:
avr-nm -Crtd --size-sort the_program.elf | grep -i ' [dbv] '

avr-nm is the utility for displaying the symbol table. It is normally
packaged with the Arduino IDE. It is invoked here with the following
options:

--size-sort is quite explicit
-C means “demangle the C++ names”
-r means “reverse sort”, i.e. sort from largest to smallest
-td means “display numbers in decimal rather than hexadecimal”

This will output the list of all symbols that have a size, in three
columns: size, type and name. You are only interested in the symbols
that consume RAM, i.e. those of type b (BSS, or uninitialized data),
d (initialized data) and v (vtable), either in upper or lower case.
The grep command is a standard Unix utility which is used here to
extract only the relevant lines from the output of avr-nm.
Example output for a small program:
00000068 B tx_buffer
00000068 B rx_buffer
00000034 B Serial
00000016 V vtable for HardwareSerial
00000004 B timer0_overflow_count
00000004 B timer0_millis
00000002 b loop::last_print
00000001 b timer0_fract

The first 4 entries come from the Serial object. The 3 entries
starting with timer0_ are used by the Arduino timekeeping functions
(millis(), micros() and delay()). The entry named
loop::last_print is a static local variable I declared in loop().

27779: <p>When compiling a sketch, after linking, the build outputs a kind of forecast on RAM usage, e.g.:</p>

<blockquote>
  <p>Minimum Memory Usage: 1456 bytes (71% of a 2048 byte maximum)</p>
</blockquote>

<p>Is it possible to somehow get a breakdown or itemization of these 1456 bytes and details on exactly where in my code, or in included libraries, they are used? </p>
 23325: <p>This was a great question and helped me recently as I'm building quite an extensive Arduino app using a Nano (ATMega328 and 32K of program memory).
At one point I was almost out of program memory and I was a bit shocked.<br />
I didn't think the code was that large.</p>
<p><strong>My Tests and Results</strong></p>
<p>With the comments I read through the posts on this answer I decided to build a blank app and examine the results as I added libraries etc.  Here are my results (<em>Using Arduino IDE 1.8.13</em>):</p>
<ol>
<li><p> blank sketch takes up 444 bytes of program storage space (max is 30720 bytes).</p>
</li>
<li><p>Sketch which includes 6 libraries✔ uses up 6218 bytes</p>
<p><code>&lt;LiquidCrystal_I2C.h&gt;, &lt;Wire.h&gt;,&lt;ds3231.h&gt;,&lt;SD.h&gt;,&lt;EEPROM.h&gt;,&lt;SoftwareSerial.h&gt;</code></p>
</li>
<li><p>adding one line <code>Serial.begin(9600);</code> uses 6324 bytes <strong>NOTE</strong>: 6324 - 6218 = 106 bytes even though I only added 19 bytes (the characters for that line).</p>
</li>
<li><p>Adding on more line <code>Serial.print(&quot;a&quot;);</code> results in 6342 bytes used. That's 18 more bytes (6324 - 6342 = 18) which is the exact number of characters I added with that line (including semicolon).</p>
</li>
<li><p>Adding a 2nd line with <code>Serial.print(&quot;a&quot;);</code> results in 6358 (16 bytes)</p>
</li>
<li><p>Adding a 3rd line of <code>Serial.print(&quot;a&quot;);</code> results in 6374 (16 additional bytes).</p>
</li>
</ol>
<p>I hope this helps a bit. I'm going back to my app now and removing all the Serial lines I used for debug output.  They're just eating up program memory now.
Actually, I'll probably even use the conditional compilation (<a href="https://stackoverflow.com/questions/57554719/how-to-provide-conditional-compilation-to-arduino-code">shown in this SO answer</a>) so I can still print when in debug.</p>
<p> Blank sketch means one with only the <code>void setup() {} void loop() {}</code> structures and nothing else.</p>
<p>✔ These are the libraries which I am using in my project.</p>
<p> I came back and added these additional lines with the amount of Program Memory used because there was a comment that lines of code do not impact memory at all. Of course they do.  At some point all Program Memory is used up and your program will no longer fit into flash.  This is what I was having a challenge with as my extensive program (which includes sensors, LCD, sd card, and bluetooth) continues to grow.</p>
 3917: <p>Looking at an assembly listing of your code is the most direct method for finding out details of space allocation.  On my Ubuntu Linux system, I use a shell script (that is, a file containing shell commands) like the following to produce an assembly listing of the most-recently-compiled <code>.ino</code> file, which must be in the working directory when the script executes:</p>

<pre><code>#!/bin/sh
# Look for .ino in current directory, and find recent /tmp/build...
item=*.ino
[ -z "$item" ] &amp;&amp; echo ino file not found &amp;&amp; exit
BDIR=/tmp/$(ls -t /tmp | egrep -m1 build.*tmp)
BASE=$(basename $item .ino)
avr-objdump -S -I$PWD $BDIR/$BASE.cpp.elf &gt; $BASE.ino.asm
</code></pre>

<p>All the stuff before the <code>avr-objdump</code> line allows the script to find out the name of the current <code>.ino</code> file and the name of the <code>/tmp/</code> subdirectory where the <code>.ino</code>'s <code>.elf</code> file is found.</p>

<p>You can also use <code>avr-objdump</code> to get a more concise size listing, as follows, where <code>$BDIR</code> and <code>$BASE</code> are as in the script above and represent the build directory in <code>/tmp/</code>, and the basename of the <code>.ino</code> file.</p>

<pre><code>avr-objdump -C -d $BDIR/$BASE.cpp.o| egrep -C2 '^Disassembly' | egrep -v '^--|^$|^Disassembly' | less
</code></pre>

<p>This will produce a list with two-line entries like the following, in which each line beginning with 00000000 is a subroutine name, and the next line shows the last line of its compiled code.  In this example output, the <code>setup_PowerDown()</code> routine has <code>0xA4</code> bytes of code, ISR <code>__vector_13</code> has <code>0xC6</code> bytes, <code>keepAlive()</code> has <code>0x10</code> bytes, etc.</p>

<pre><code>00000000 &lt;setup_PowerDown()&gt;:
  a4:   08 95           ret
00000000 &lt;__vector_13&gt;:
  c6:   18 95           reti
00000000 &lt;keepAlive()&gt;:
  10:   08 95           ret
00000000 &lt;eeWrite1(unsigned char, unsigned char)&gt;:
  3a:   08 95           ret
00000000 &lt;eeWrite2(unsigned char, unsigned char)&gt;:
  18:   0c 94 00 00     jmp     0       ; 0x0 &lt;eeWrite2(unsigned char, unsigned char)&gt;
00000000 &lt;parValidate(unsigned char, unsigned char, unsigned char)&gt;:
  64:   08 95           ret
00000000 &lt;loadSettings()&gt;:
  e0:   08 95           ret
00000000 &lt;applySettings()&gt;:
  84:   08 95           ret
</code></pre>

<p>Some IDEs provide symbol table information that includes sizes of routines, stack frames, and data.  I don't know if that's available via Arduino IDE, AVR-libc, or <a href="http://www.sourceware.org/binutils/" rel="nofollow noreferrer">GNU Binutils</a>.  The symbol table provided by <code>avr-readelf -s</code> (as in following command) provides quite detailed symbol information that seems quite useless in its raw form.</p>

<pre><code>avr-readelf  -s  $BDIR/$BASE.cpp.o
</code></pre>

<p>The methods described above are somewhat ad hoc, and depend on files left after <code>avr-gcc</code> or <code>avr-g++</code> run.  I don't know of any “official” methods for getting the information you want to see. </p>
 4143: <p>You can automatically generate a "map" file every time you compile. This gives you a full breakdown of how everything is linked together by the linker, including the size of each section and other useful debugging information.</p>

<p>A simple modification to platforms.txt in <code>hardware/arduino/avr</code> is all that is needed.  Find the line starting <code>compiler.c.elf.flags=</code> and add to the end of it:</p>

<pre><code> -Wl,-Map,"{build.path}/{build.project_name}.map"
</code></pre>

<p>If you like you can replace <code>{build.path}</code> with a hard-coded path, such as your desktop, and the <code>.map</code> with <code>.txt</code> to allow it to easily be opened by notepad or whatever you use (assuming Windows, of course).</p>
 7508: <p>Since you seem interested about RAM, rather than flash usage, I suggest
you look at the symbol table of your compiled program, which will be
more telling than the disassembly. On my Linux system, I usually do the
following:</p>

<pre><code>avr-nm -Crtd --size-sort the_program.elf | grep -i ' [dbv] '
</code></pre>

<p><code>avr-nm</code> is the utility for displaying the symbol table. It is normally
packaged with the Arduino IDE. It is invoked here with the following
options:</p>

<ul>
<li><code>--size-sort</code> is quite explicit</li>
<li><code>-C</code> means “demangle the C++ names”</li>
<li><code>-r</code> means “reverse sort”, i.e. sort from largest to smallest</li>
<li><code>-td</code> means “display numbers in decimal rather than hexadecimal”</li>
</ul>

<p>This will output the list of all symbols that have a size, in three
columns: size, type and name. You are only interested in the symbols
that consume RAM, i.e. those of type <code>b</code> (BSS, or uninitialized data),
<code>d</code> (initialized data) and <code>v</code> (vtable), either in upper or lower case.
The <code>grep</code> command is a standard Unix utility which is used here to
extract only the relevant lines from the output of <code>avr-nm</code>.</p>

<p>Example output for a small program:</p>

<pre><code>00000068 B tx_buffer
00000068 B rx_buffer
00000034 B Serial
00000016 V vtable for HardwareSerial
00000004 B timer0_overflow_count
00000004 B timer0_millis
00000002 b loop::last_print
00000001 b timer0_fract
</code></pre>

<p>The first 4 entries come from the <code>Serial</code> object. The 3 entries
starting with <code>timer0_</code> are used by the Arduino timekeeping functions
(<code>millis()</code>, <code>micros()</code> and <code>delay()</code>). The entry named
<code>loop::last_print</code> is a static local variable I declared in <code>loop()</code>.</p>
