When a process is forked, linux does a very minimal amount of copying, and utilizes a copy-on-write method. This copy on write means that if both processes (the parent and the child) are doing reads, they will read from the exact same blocks of memory. Once one of them writes to that memory, it is copied and no longer shared.
Now the programs do not know this is happening. This is because the kernel maintains a page table for each process. When the process says 'I want to access memory 0xbeef' the kernel remaps that into an actual location in physical memory. This is necessary because the program will store these addresses in variables, so when the program is forked, it cant know if or where data in its memory gets moved to (all those addresses stored in the variables have to continue to be valid).
This is also what enables swap to work. The kernel can take the physical memory holding the data and store it to a disk, but the program will still reference address 0xbeef, and the kernel will translate that.
So the absolute minimum that the kernel ends up copying is the page table that does this address mapping, and the task structure (covers opened files, process state, pending signals, etc).