This answer is by no means exhaustive but it may explain it enough to make things click.
In virtual memory systems, there is a disconnect between logical and physical addresses.
An application can be given a virtual address space of (let's say) 4G. This is its usable memory and it's free to use it as it sees fit. It's a nice contiguous block of memory (from the point of view of the application).
However, it is not the only application running, and the OS has to mediate between them all. Underneath that nice contiguous model, there is a lot of mapping going on to convert logical to physical addresses.
With this mapping, the OS and hardware (I'll just call these the lower layers from here on in) is free to put the application pages anywhere it wants (either in physical memory or swapped out to secondary storage).
When the application tries to access memory at logical address 50, the lower levels can translate that to a physical address using translation tables. And, if it tries to access logical memory that's been swapped out to disk, a page fault is raised and the lower levels can bring the relevant data back into memory, at whatever physical address it wants.
In the bad old days when physical addresses were all you had, code had to be relocatable (or fixed up on load) since it could load anywhere. With virtual memory, that code (and data) can be at logical memory location 50 in a dozen different processes at the same time - it's actual physical address will be different however.
It can even be shared so that one physical copy exists in the address space of many processes at once. This is the crux of shared code (so we don't use more physical memory than we need) and shared memory to allow easy inter-process communication).
It is, of course, less efficient than a pure physical-address environment but the CPU manufacturers try to make it as insanely efficient as possible, since it's used heavily. The advantages far outweigh the disadvantages.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…