Your question is quite broad and thus hard to answer correctly. In concept a reference is an alias to the object. How a specific compiler implements this concept can vary, especially after optimization. In many cases the implementation essentailly uses a pointer to the object, in which case the reference requires memory and what is stored there is probably just the address of the object.
struct S1{
int & ri;
S1(int &i):ri{i}{}
};
In this case I would expect the compiler to need memory in order to hold the reference.
struct S2{
int i;
int& ri;
S2():ri{i}{}
};
In this case the reference may not need memory.
At the end of the day one cannot rely on the way a particular compiler in a particular version handles references.
Whether you think of a reference as an alias or as a pointer which must always point to an object (i.e. never nullptr) and always points to the same object (i.e. const) and is automatically dereferenced in your own understanding of a piece of code is probably not important.
Although one can create a "null reference" like
int *i= nullptr;
int& ri=*i;
this is undefined behavior as explained here: Assigning a reference by dereferencing a NULL pointer
Undefined behavior means anything can happen, it might seem that on your compiler the reference still acts like a null pointer, however here are a few edxamples where the compiler could act quite oddly (and is allowed to with no error or warning)
int i;
//...
if(&i) {} //always true
else {
//optimized away
}
int* i;
//...
if(i){}
else{
//not optimized away
}
int *i = nullptr;
int& ri = *i;
//...
if(&ri){} //could be assumed always true!
else{
//could be optimized away !!
}
int *i =nullptr;
*i++; //runtime error, convention says user should have checked for nullness
int& ri = i;
ri++; //probably runtime error, user does not know to check for nullness and may not be able to because of optimization assuming &ri ! nullptr
struct S{
int i[1001];
};
S* s = nullptr;
S& rs = *s;
if(&rs){ //could be assume always true
rs.i[1000] = 4; //may not result in runtime error, address could be 0x4000,
// probably still not valid on a pc, on an embedded processor you could be
// changing clock speed or something nasty even though you checked for
// nullness!!!! Undefined behavior sucks!
}