mmap 可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针而不需要 read/write 函数。
1. 虚拟内存
https://welkinx.com/2020/02/07/mmap/
1.1 Linux 增加交换空间
未开启交换空间:
1 | sudo su |
已开启交换空间,重新修改 swap 大小:
1 | # 查看内存使用情况 |
1.2 创建虚拟内存实例
1.2.1 创建虚拟内存、在虚拟内存中读入大文件数据并存储
注意 placement new 表达式的用法,其中 new(place) 中 place 为指针,指向预分配的内存地址。
点击查看
1 |
|
2. mmap
https://www.cnblogs.com/huxiao-tee/p/4660352.html
2.1 mmap 简介
mmap 可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针而不需要 read/write 函数。
此函数的作用是创建一个新的虚拟内存区域,并将指定的对象映射到此区域。
内存映射(Memory Mapping)将文件内容映射到进程的虚拟地址空间。在这种机制下,文件可以被视为内存的一部分,从而允许程序直接对这部分内存进行读写操作,而无需传统的文件 I/O 调用,从而减少系统的用户态、内核态切换,减少切换开销。通过这种方式,文件内容可以通过指针直接访问,就像访问普通的内存数组一样,这极大地提高了文件操作的效率和直观性。
映射时,操作系统将文件的一部分或全部内容映射到虚拟内存地址空间。这些虚拟地址与物理内存地址相关联,但并不是所有数据立即加载到物理内存中。
当访问映射的地址时,如果对应数据不在物理内存中,操作系统会自动从磁盘加载所需的数据页到物理内存中(这称为“页错误”处理)。
2.2 mmap 特点
2.2.1 数据持久化
通过 mmap 映射的数据通常来自文件系统中的文件。这意味着数据是持久化的,即使程序终止,文件中的数据依然存在。当你通过映射的内存区域修改数据时,这些更改最终会反映到磁盘上的文件中。
2.2.2 大文件读写
mmap 特别适合于需要频繁读写大文件的场景,因为它可以减少磁盘 I/O 操作的次数。它也允许文件的一部分被映射到内存中,这对于处理大型文件尤为有用。
2.2.3 性能和效率
映射文件到内存可以提高文件访问的效率,尤其是对于随机访问或频繁读写的场景。系统可以利用虚拟内存管理和页缓存机制来优化访问。
2.2.4 同步和一致性
使用 mmap 时,必须考虑到文件内容的同步问题。例如,使用 msync
调用来确保内存中的更改被同步到磁盘文件中。
2.2.5 页缓存
使用 mmap 映射文件到内存时,操作系统利用页缓存(提升文件读写效率。在内存上,与文件中的数据块进行绑定。文件被划分为多个页大小的数据块)来优化对这些文件数据的访问。页缓存是操作系统的一部分,用于存储从磁盘读取的数据页。 访问 mmap 映射的文件时,并不是每次读取都会直接触及磁盘。如果所需数据已经在页缓存中(由于之前的读取操作),则直接从缓存中获取数据,而不需要磁盘 I/O。
2.3 mmap 函数介绍
1 | void *mmap(void *addr, size_t len, int prot, |
2.3.1 参数
addr
: 内存上的映射地址,给内核一个提示(建议),从(内存上)什么地址开始映射。建立映射后,真正的映射首地址通过返回值得到。如果addr
为空,则内核自己选择合适的地址。len
: 需要映射的那部分文件的长度(多少个字节),代表将文件中多大的部分映射到内存。prot
: 4 个取值PROT_EXEC
: 映射部分可执行,如动态库PROT_READ
: 映射部分可读PROT_WRITE
: 映射部分可写PROT_NONE
: 映射部分不可访问
flags
: 2 个取值MAP_SHARED
: 多个进程对相同映射文件共享MAP_PRIVATE
: 多个进程对相同映射文件不共享
filedes
: 文件描述符。文件描述符是内核为了高效管理已经被打开的文件的索引,是一个非负整数,用于指代被打开的文件。文件描述符可以通过系统函数open()
或create()
获取,也可以从父进程继承,用于进行文件操作或网络通信。offset
: 从文件的什么位置开始映射,必须是页(内存上)大小的整数倍。
2.3.2 返回值
返回值为 void*
指针,因此可以进行各种类型转换,如 int*
、char*
等。C++ 中不能直接 int* p = mmap()
,需要对 mmap()
进行类型转换,如 int* p = (int*)mmap()
。
2.3.3 需要的头文件
1 |
2.4 mmap 实例
2.4.1 简单对文件进行修改
1 |
|
2.4.2 读取 bvecs 文件
1 | std::vector<std::vector<float>> mmap_read_bvecs(std::string &filename) |
3. 虚拟内存分配例子
3.1 mmap_read_bvecs
mmap_read_bvecs
函数单独写在一个 cpp 文件中
1 |
|
3.2 virtual_mem_test
直接调用 Linux API,手动创建虚拟内存后,在虚拟内存中开辟空间
1 | int main() |
3.3 boost_interprocess_test
使用 Boost::interprocess 库,共享内存。在磁盘上创建一块空间用于文件映射。
1 |
|
3.4 mimalloc_test
使用 mimalloc
内存分配器分配虚拟内存。
1 |
|