Click the above blue text to follow us
In Linux systems, Memory-Mapped I/O is an advanced I/O mechanism designed to provide direct access to files by mapping them into the process’s address space.
Through this method, data can be accessed directly via memory without the need for system calls to transfer data, thereby improving file operation efficiency. Next, we will delve into its working principles, key functions, and its advantages and disadvantages in various application scenarios.
Memory-Mapped I/O is based on the concept of memory regions. Once the content of a file is mapped into memory, applications can access the file content directly as if accessing regular memory. File read and write operations can be performed by reading from and writing to memory, eliminating the overhead of transferring data back and forth between kernel space and user space using the read() and write() functions.
Key Features:
- Direct Memory Operations: Reading file content requires only accessing memory, and writing to a file only requires writing data to memory.
- Reduced System Call Overhead: Frequent calls to read() and write() system calls are unnecessary, reducing the complexity of I/O.
- Improved Efficiency for Large File Operations: Suitable for scenarios requiring frequent or large data interactions.
1
mmap() and munmap() Functions
The core function of Memory-Mapped I/O is mmap(), which is used to map a file into the process’s address space, and munmap() is used to unmap it.
The prototype of the mmap() function is as follows:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
Parameter Details:
- addr: Specifies the starting address of the mapping. Typically set to NULL, indicating that the system will choose the starting address.
- length: The length of the mapping (in bytes), determining the size of the file mapping area.
- offset: The file offset, usually 0, indicating mapping starts from the file’s head.
- fd: The file descriptor indicating the file to be mapped.
- prot: The protection permissions of the mapping area, which can be set to:
- PROT_EXEC: Executable;
- PROT_READ: Readable;
- PROT_WRITE: Writable;
- PROT_NONE: Inaccessible.
- flags: The attribute flags of the mapping area. Common settings include:
- MAP_SHARED: Changes to the shared mapping area will be written to the file and can be shared with other processes.
- MAP_PRIVATE: Private mapping, where written data is only visible to the current process and does not affect the file itself.
Return Value: Returns the starting address of the mapping area on success; returns -1 on failure, typically indicated by MAP_FAILED, and sets errno.
Notes: addr and offset usually need to be multiples of the system page size. You can use sysconf(_SC_PAGE_SIZE) to obtain the system page size.
The prototype of the munmap() function is as follows:
int munmap(void *addr, size_t length);
Parameter Details:
- addr: The starting address of the mapping.
- length: The length to unmap, which must be a multiple of the page size.
Return Value: Returns 0 on success; returns -1 on failure and sets errno.
2
Other Related Functions
When using mmap() to map files, you can also manage the mapping area through the following system calls.
mprotect() is used to change the protection attributes of the mapping area, with the following prototype:
int mprotect(void *addr, size_t len, int prot);
Parameters:
- addr and len define the address range for which the protection attributes need to be changed.
- prot is the new protection attribute (same as the prot parameter of mmap()).
msync() ensures that the data in the mapping area is synchronized to the disk file, similar to fsync(), to ensure data consistency. The prototype is as follows:
int msync(void *addr, size_t length, int flags);
Parameters:
- addr and length: Specify the memory area to be synchronized.
- flags:
- MS_ASYNC: Asynchronous synchronization.
- MS_SYNC: Synchronous mode.
- MS_INVALIDATE: Requests to invalidate other mappings of the same file to update with new values.
3
Signals and Exception Handling
Signals that may be raised during the use of Memory-Mapped I/O mainly include SIGSEGV and SIGBUS.
- SIGSEGV: Triggered when the mapping area is set to read-only, and the process attempts to write to that mapping area.
- SIGBUS: Triggered when a part of the mapping area no longer exists, such as when the file is truncated, causing the mapping area to exceed the file’s range.
4
Comparison of Memory-Mapped I/O and Regular I/O
5
Application Scenarios and Limitations
Advantageous application scenarios:
- Large Data Processing: Suitable for scenarios requiring frequent access to large files or continuous data, such as video editing and image processing.
- Shared Memory: mmap() is similar to inter-process shared memory and can be used for efficient data sharing between processes.
Limitations:
- File Size Limitations: The mapping area of the file is fixed and cannot exceed the actual size of the file.
- Page Size Constraints: The starting address, offset, and length of the mapping area usually need to be multiples of the page size.
- Data Consistency: Care must be taken with file write synchronization; to ensure real-time data updates, msync() can be used.
Linux Memory-Mapped I/O is an efficient I/O method, particularly suitable for large data scenarios.
In application scenarios, it significantly reduces I/O operation latency and the frequency of system calls by directly mapping files into the process’s virtual memory, making efficient data sharing and file access possible.
However, due to limitations such as file size, page size alignment, and data synchronization, developers need to choose between Memory-Mapped I/O and regular I/O based on the application scenario.
Click to read the original text for more exciting content~