Is merging pages allowed in mmap?
As described here
The
munmap()
function shall remove any mappings for those entire pages
containing any part of the address space of the process starting at
addr
and continuing forlen
bytes.
so it is allowed to remove multiple mappings with a single munmap
call (as if it was a single mapping).
There is a problem with your code though: how do you know if a page (p2
) before your page (p1
) is not used? It could be already allocated by other pars of the program (including malloc
), by using MAP_FIXED
like this you will rewrite (remap) its content:
When
MAP_FIXED
is set in the flags argument, the implementation is
informed that the value of pa shall beaddr
, exactly. IfMAP_FIXED
is
set,mmap()
may returnMAP_FAILED
and seterrno
to[EINVAL]
. If a
MAP_FIXED
request is successful, the mapping established bymmap()
replaces any previous mappings for the process' pages in the range
[pa,pa+len)
.
So I don't think this trick can be useful in the general case, you should use mremap
instead.
As for how this is implemented: Linux does merge sequential private anonymous mappings, so both will be merged into a single vma_struct
in the kernel. This "feature" has undesirable side effects such as munmap
failing to free memory with ENOMEM
. But this is more of an implementation detail, not something you have control over.
Why does munmap needs a length as parameter?
One can map
, say, 5 pages and later unmap
one of them. And information about what pages to unmap is passed as address and length where the length is a multiple of page size.
What is the purpose of MAP_ANONYMOUS flag in mmap system call?
Anonymous mappings can be pictured as a zeroized virtual file.
Anonymous mappings are simply large, zero-filled blocks of memory ready for use.
These mappings reside outside of the heap, thus do not contribute to data segment fragmentation.
MAP_ANONYMOUS + MAP_PRIVATE:
- every call creates a distinct mapping
- children inherit parent's mappings
- childrens' writes on the inherited mapping are catered in copy-on-write manner
- the main purpose of using this kind of mapping is to allocate a new zeroized memory
- malloc employs anonymous private mappings to serve memory allocation requests larger than MMAP_THRESHOLD bytes.
typically, MMAP_THRESHOLD is 128kB.
MAP_ANONYMOUS + MAP_SHARED:
- each call creates a distinct mapping that doesn't share pages with any other mapping
- children inherit parent's mappings
- no copy-on-write when someone else sharing the mapping writes on the shared mapping
- shared anonymous mappings allow IPC in a manner similar to System V memory segments, but only between related processes
On Linux, there are two ways to create anonymous mappings:
specify MAP_ANONYMOUS flag and pass -1 for fd
addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
exit(EXIT_FAILURE);open /dev/zero and pass this opened fd
fd = open("/dev/zero", O_RDWR);
addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);(this method is typically used on systems like BSD, that do not have MAP_ANONYMOUS flag)
Advantages of anonymous mappings:
- no virtual address space fragmentation; after unmapping, the memory is immediately returned to the system
- they are modifiable in terms of allocation size, permissions and they can also receive advice just like normal mappings
- each allocation is a distinct mapping, separate from global heap
Disadvantages of anonymous mappings:
- size of each mapping is an integer multiple of system's page size, thus it can lead to wastage of address space
- creating and returning mappings incur more overhead than that of from the pre-allocated heap
if a program containing such mapping, forks a process, the child inherits the mapping.
The following program demonstrates this kinda inheritance:
#ifdef USE_MAP_ANON
#define _BSD_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
/*Pointer to shared memory region*/
int *addr;
#ifdef USE_MAP_ANON /*Use MAP_ANONYMOUS*/
addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED) {
fprintf(stderr, "mmap() failed\n");
exit(EXIT_FAILURE);
}
#else /*Map /dev/zero*/
int fd;
fd = open("/dev/zero", O_RDWR);
if (fd == -1) {
fprintf(stderr, "open() failed\n");
exit(EXIT_FAILURE);
}
addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
fprintf(stderr, "mmap() failed\n");
exit(EXIT_FAILURE);
}
if (close(fd) == -1) { /*No longer needed*/
fprintf(stderr, "close() failed\n");
exit(EXIT_FAILURE);
}
#endif
*addr = 1; /*Initialize integer in mapped region*/
switch(fork()) { /*Parent and child share mapping*/
case -1:
fprintf(stderr, "fork() failed\n");
exit(EXIT_FAILURE);
case 0: /*Child: increment shared integer and exit*/
printf("Child started, value = %d\n", *addr);
(*addr)++;
if (munmap(addr, sizeof(int)) == -1) {
fprintf(stderr, "munmap()() failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
default: /*Parent: wait for child to terminate*/
if (wait(NULL) == -1) {
fprintf(stderr, "wait() failed\n");
exit(EXIT_FAILURE);
}
printf("In parent, value = %d\n", *addr);
if (munmap(addr, sizeof(int)) == -1) {
fprintf(stderr, "munmap()() failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
Sources:
The Linux Programming Interface
Chapter 49: Memory Mappings,
Author: Michael Kerrisk
Linux System Programming (3rd edition)
Chapter 8: Memory Management,
Author: Robert Love
How to unmap an mmap'd file by replacing with a mapping to empty pages
On Linux you can use mmap
with MAP_FIXED
to replace the mapping with any mapping you want. If you replace the entire mapping the reference to the file will be removed.
Related Topics
How to Start a Shell Without Any User Configuration
Cmd 2>&1 > Log VS Cmd > Log 2>&1
What Does "Bash:No Job Control in This Shell" Mean
Shellscript to Monitor a Log File If Keyword Triggers Then Execute a Command
Error: Gdal-Config Not Found While Installing R Dependent Packages Whereas Gdal Is Installed
How to Get a List of All Valid Ip Addresses in a Local Network
How to Convert Spaces to Tabs in Vim or Linux
How to List the Contents of a Package Using Yum
How to Send Data to Local Clipboard from a Remote Ssh Session
How to Perform Grep Operation on All Files in a Directory
Encrypt a String Using Openssl Command Line
Using Find - Deleting All Files/Directories (In Linux ) Except Any One