Process memory defragmentation by another process
Posted: 2018-01-14, 8:06:27
I came up with an idea for an algorithm that effectively can decrease to completely eliminate memory fragmentation.
When we try to expand the memory space of a process without having enough of a gap before/behind the already allocated space, we would allocate a new block of memory somewhere else, then create an entry in our memory map to extend our address space to the new block, using an offset. The algorithm i came up with lets an other process merge these blocks together without interrupting the application process unless absolutely necessary.
The naive solution would be to interrupt the process, merge the blocks, then resume execution. This would result in a spike of latency similar to a big garbage collection run of some managed programming lanuages. These are sometimes not tolerable. The idea I came up with uses another process to do the defragmentation, therefore leaving the application thread running unless it accesses the block that is currently moved. Naturally, this approach comes with a higher system level overhead.
The critical requirement for this to work is that a memory map of a running process can be atomically patched by another process. This might actual be too complicated to be feasible for real implementations, I find this idea to be interesting nonetheless.
In the following example, I assume the case that we expanded the high end of the process address space and now have enough free space behind the old block to move the expanded block behind it. The memory map entry for the expanded block is just over the entry of the old block, therefore we have no gap in our adress space.
The memory block to be moved is named Block A.
A memory entry without acces rights is called entry E.
- Allocate the needed space
- Determine a transfer block size
- Set up a custom access violation handler for the application process
- Add entry E between both blocks in the memory map, the address is the same as for the entry of block A
- for each transfer block of block A, starting at the lowest address:
-> increase the address of the memory map entry for block A by the transfer block size
-> copy current transfer block of block A to the new position
-> increase the address for entry E by the transfer block size
- delete entry E and the entry for block A.
- deallocate the old space
- reset the access violation handler
If the application process accesses memory in the address range of entry E, it triggers the custom handler. This handler checks if the accessed address is indeed in the range of entry E. If so, it simply waits until the current transfer block finished, then lets the process resume execution. If not, the standard access violation handler is called.
What do you think of this?
When we try to expand the memory space of a process without having enough of a gap before/behind the already allocated space, we would allocate a new block of memory somewhere else, then create an entry in our memory map to extend our address space to the new block, using an offset. The algorithm i came up with lets an other process merge these blocks together without interrupting the application process unless absolutely necessary.
The naive solution would be to interrupt the process, merge the blocks, then resume execution. This would result in a spike of latency similar to a big garbage collection run of some managed programming lanuages. These are sometimes not tolerable. The idea I came up with uses another process to do the defragmentation, therefore leaving the application thread running unless it accesses the block that is currently moved. Naturally, this approach comes with a higher system level overhead.
The critical requirement for this to work is that a memory map of a running process can be atomically patched by another process. This might actual be too complicated to be feasible for real implementations, I find this idea to be interesting nonetheless.
In the following example, I assume the case that we expanded the high end of the process address space and now have enough free space behind the old block to move the expanded block behind it. The memory map entry for the expanded block is just over the entry of the old block, therefore we have no gap in our adress space.
The memory block to be moved is named Block A.
A memory entry without acces rights is called entry E.
- Allocate the needed space
- Determine a transfer block size
- Set up a custom access violation handler for the application process
- Add entry E between both blocks in the memory map, the address is the same as for the entry of block A
- for each transfer block of block A, starting at the lowest address:
-> increase the address of the memory map entry for block A by the transfer block size
-> copy current transfer block of block A to the new position
-> increase the address for entry E by the transfer block size
- delete entry E and the entry for block A.
- deallocate the old space
- reset the access violation handler
If the application process accesses memory in the address range of entry E, it triggers the custom handler. This handler checks if the accessed address is indeed in the range of entry E. If so, it simply waits until the current transfer block finished, then lets the process resume execution. If not, the standard access violation handler is called.
What do you think of this?