网站首页 > 文章精选 正文
API
- Linux: mmap
- Windows: CreateFileMapping
- Java: FileChannel.map
原理解读
分页机制
- 32位系统下,每个进程都能看到独立的4GB虚拟内存空间, 每个进程都有一套对应的页目录和页表映射物理内存,页目录和页表并不会映射全部的4GB物理内存,只会映射已经分配的物理内存. 这就是所谓的进程间的内存隔离和内存资源分配单位. 而进程切换就是切换对应的页目录和页表以及对应的寄存器.
- 而内核空间(高2GB)是所有进程都需要公用的, 所以页目录和页面也有公用部分, 这就达到了多进程共享虚拟内存空间的效果.
内存映射文件
- 分配物理页(物理内存以页为单位,windows下是4kb)
- 把已分配的物理页映射到公用的页目录和页表下
- (可选) 把磁盘文件的数据读取到对应已映射好的共享虚拟内存, 或置换虚拟内存的数据到磁盘文件
基于以上特性的实际应用
进程间通信
以Windows为例
//写进程
void demo() {
HANDLE hFile = CreateFile(TEXT(R"(D:\tmp\test.txt)"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 1024, TEXT("testFileMapping"));//1K的内存文件
//HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, TEXT("testFileMapping"));//无文件
if (hFileMapping == NULL) {
throw Exception(0,"创建文件映射失败");
}
LPVOID p = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
if (p == NULL) {
throw Exception(0, "创建文件映射失败");
}
memcpy(p, "hello", 5);
UnmapViewOfFile(p);
CloseHandle(hFileMapping);
CloseHandle(hFile);
}
//读进程
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) {
HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, TRUE, TEXT("testFileMapping"));//1K的内存文件
if (hFileMapping == NULL) {
return 0;
}
LPVOID p = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
if (p == NULL) {
return 0;
}
char* buff[1024] = {0};
memcpy(buff, p, 5);
MessageBoxA(NULL, (const char*)buff, "title", MB_OK);
UnmapViewOfFile(p);
CloseHandle(hFileMapping);
}
读取大文件
内存映射文件,使程序可以像操作内存一样直接访问文件内容,而不需要显式地调用read或write方法。这种操作方式不仅可以简化代码,还能显著提升文件I/O的性能,特别是在处理大文件或频繁访问文件内容的场景中. 以Java为例子
public static void mmap() throws IOException {
RandomAccessFile file = new RandomAccessFile("example.txt","rw");
FileChannel channel = file.getChannel();
//直接把文件映射到内容中,从而直接修改/读取文件
MappedByteBuffer buffer =channel .map(FileChannel.MapMode.READ_WRITE, 0, file.length());
//读
char c = buffer.getChar(0);
//写
buffer.putChar(0,'a');
channel.close();
file.close();
}
零拷贝
以如上场景为例, 从本地磁盘上读取一个文件,然后通过socket连接,发送给客户端
操作系统首先需要将磁盘中的文件读取到内核态的页缓存,然后加载到用户态的应用程序中,这样服务端应用程序才能拿到文件的内容。而服务端应用程序往客户端发送文件内容时,也需要先将文件写入内核态的Socket缓冲区,然后才能通过Socket往客户端发送消息。整个过程中有四次文件拷贝。
- 所谓零拷贝,主要任务就是要避免这个过程中的CPU拷贝,让CPU从这些繁重毛时的拷贝任务中解脱出来。这其中,硬件与页缓存之间的交互过程,已经可以通过DMA(直接存储器存储)进行,不需要CPU参与,所以,零零拷贝的重点就在于减少内核态与用户态之间的文件拷贝
- mmap: 内存映射文件,避免用户态与内核态之间的数据拷贝
- sendfile: 它允许内核态直接将文件数据直接发送到套接字,无需在用户空间和内核空间之间复制数据
猜你喜欢
- 2025-03-14 C语言中内存四区的详解(c语言内存分为几个区)
- 2025-03-14 别等涨价再后悔 大内存这样玩(大内存有什么用)
- 2025-03-14 Linux运维获取内存、cpu、磁盘IO信息
- 2025-03-14 用自己电脑做云存储空间,用自己电脑做云存储的数据备份方法
- 2025-03-14 Win10下C盘爆满,只剩500MB!我一怒之下最终清理出70G空间!
- 2025-03-14 傻傻分不清?内存条和固态硬盘区别来了
- 2025-03-14 微信占几十G Mac空间?可以这样一键导出旧聊天文件
- 2025-03-14 深圳尚学堂:关于java内存管理的基础知识
- 2025-03-14 计算机原理:内存和硬盘的关系你真的知道吗?
- 2025-03-14 在windows中,5招教你释放硬盘空间,让系统和重装一样干净
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)