The usual term that's flung around is that string literals are 'interned'. It is a pretty meaningless term and doesn't describe what is really going on that well.
A .NET assembly contains two chunks of data, the metadata and the IL. Metadata is primary used to describe the types in the assembly and contains resources. IL is the code that you wrote, translated to the Intermediate Language format.
The metadata section has 5 tables, one of these is called the "string table". Highly descriptive of what it contains, that's where your "Hello" string is stored. It is already in a format that's identical to the way strings are normally stored in the garbage collected heap, but with an extra flag in the object header that indicates that it is a string literal and not stored in the heap.
The assembly content is mapped into virtual memory by a memory mapped file, exact same animal as the .NET System.IO.MemoryMappedFiles.MemoryMapFile class. The strTemp object reference will be initialized by a single MOV instruction emitted by the jitter and stores a pointer that directly points at the string table entry in mapped view of the file. First time your program actually uses the string content, an operating system page fault ensures that the string will be present in RAM.
The garbage collector will find the strTemp object reference whenever it performs a collection. But will just ignore the reference, the flag in the object header says that it should since the string object isn't actually stored in the garbage collected heap. Which is really what "interning" means.