Well, a reference is data (it's a memory address), so yes, it has to be stored somewhere. Whether it goes in memory or into a register depends entirely on compiler optimizations.
Well you have to consider that Rust references (may they be immutable & or mutable &mut) are under the hood "just" pointers. And obviously, a pointer needs to be stored somewhere (like H2CO3 already mentioned). But the Rust compiler can make some special checks on those references (but not for unsafe pointers), so you never use them in a wrong or illegal way. I may be wrong, but references &T use the pointer type * const T and &mut use the pointer type * mut T internally.
For example, the size of primitives types (u8, i16, usize, etc) should be stable across compilations, so are the pointer types (* const T, * mut T), if T is Sized:
let size = std::mem::size_of::<u8>(); // size = 1
let size = std::mem::size_of::<usize>(); // size = 8
let size = std::mem::size_of::<*const u8>(); // size = 8
struct Person {
name: String,
age: u8,
children: Vec<String>,
}
let size = std::mem::size_of::<Person>(); // size = 56
let size = std::mem::size_of::<*const Person>(); // size = 8
let size = std::mem::size_of::<*mut Person>(); // size = 8
Note that *const T and *mut T always have the same size.
To answer your question: "Do the two programs consume the same memory?" The theoretical answer is no, because you declared two references/pointers which have to be stored somewhere. Practically, I could imagine the compiler will optimize your code and will see the usage of r1 and r2 are identical, and only one reference is necessary to achieve the program logic, so one reference can be eliminated in the compiled code.
Furthermore, since the references are used only for printing, and printing will dereference them anyway, optimizer may remove both references and use the original &str.