The 8086 does not have a protected mode: every process has full access to everything, which is a nightmare for an OS designer.
The processor had a set of registers specially designed to handle the segments: CS (code), DS (data), SS (stack), and ES (extra spare one). These could then be used in combination with a set of pointer register to address 64K for each segment. However, the code had to handle these under its own responsibility. So compilers adopted typical memory models for generating the code, depending on whether or not the 64K limit could be insufficient for some segments.
The main OS at that time was MS-DOS. No multi-tasking: so no worry about concurrent processes. The programme executable defined the initial memory management:
- the COM executable format was initially used. The OS simply loaded all the code at one address, initialised all the segments to the same 64K bloc, and started the programme at a fixed offset. You then had access to the machine.
- the EXE format later became more popular. It allowed to initialise and load multiple segments at different places. In the header a maximum size allows the OS to reserve initially enough space. The loading process is explained here.
MS-DOS 2 also came with a better memory management. Basically, you could allocate, increase allocation and free blocs of memory from the OS. The blocs were meant to fit in segments. But once again, the program had to manage the loading of segment and pointer register on its own. And nothing protected other parts of the memory from memory corruption.
I don't remember if the realloc at MSDOS level moved the bloc or simply returned an error if there was not enough space to extend the size of the bloc. But the standard C library fortunately provided the nice realloc() that came from the UNIX world, and ensured moving memory to a larger location if needed. Up to you to ensure that no rogue pointer still used the old location.