C/C++ 实现内存映射
C/C++ 实现内存映射
权重采用内存映射方式加载,避免了大规模内存拷贝,特别适合大模型部署。
在C语言中实现内存映射主要使用mmap()系统调用。以下是一个完整的示例,展示如何使用内存映射进行文件读写:
- 完整的内存映射工具函数
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
typedef struct {
void *addr; // 映射地址
size_t size; // 映射大小
int fd; // 文件描述符
} MappedFile;
// 打开并映射文件
MappedFile* map_file(const char *filename, size_t size, int create) {
MappedFile *mf = malloc(sizeof(MappedFile));
if (!mf) return NULL;
int flags = O_RDWR;
if (create) {
flags |= O_CREAT;
}
mf->fd = open(filename, flags, 0644);
if (mf->fd == -1) {
perror("open");
free(mf);
return NULL;
}
// 获取文件大小(如果不指定大小)
if (size == 0) {
struct stat st;
if (fstat(mf->fd, &st) == -1) {
perror("fstat");
close(mf->fd);
free(mf);
return NULL;
}
size = st.st_size;
}
// 如果是创建模式,调整文件大小
if (create && ftruncate(mf->fd, size) == -1) {
perror("ftruncate");
close(mf->fd);
free(mf);
return NULL;
}
mf->size = size;
// 创建映射
mf->addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED, mf->fd, 0);
if (mf->addr == MAP_FAILED) {
perror("mmap");
close(mf->fd);
free(mf);
return NULL;
}
printf("成功映射文件: %s, 大小: %.2f MB\n",
filename, size / (1024.0 * 1024.0));
return mf;
}
// 同步映射到磁盘
int sync_mapping(MappedFile *mf) {
if (msync(mf->addr, mf->size, MS_SYNC) == -1) {
perror("msync");
return -1;
}
return 0;
}
// 取消映射并关闭
int unmap_file(MappedFile *mf) {
if (munmap(mf->addr, mf->size) == -1) {
perror("munmap");
return -1;
}
if (close(mf->fd) == -1) {
perror("close");
return -1;
}
free(mf);
return 0;
}
// 使用示例 - 创建6GB的大文件
int main() {
// 创建新文件并映射 - 使用明确的类型转换避免警告
size_t file_size = (size_t)6 * 1024 * 1024 * 1024; // 6GB
printf("尝试创建 %.2f GB 的文件...\n", file_size / (1024.0 * 1024.0 * 1024.0));
MappedFile *mf = map_file("large_data.bin", file_size, 1);
if (!mf) {
fprintf(stderr, "映射文件失败\n");
return 1;
}
// 写入数据到文件开头
char *data = (char *)mf->addr;
sprintf(data, "这是一个 %.2f GB 的内存映射文件\n",
mf->size / (1024.0 * 1024.0 * 1024.0));
// 在文件末尾也写入一些数据
if (mf->size > 100) {
char *end_data = (char *)mf->addr + mf->size - 100;
sprintf(end_data, "文件末尾标记 - 文件大小: %zu 字节", mf->size);
}
// 同步到磁盘
printf("同步数据到磁盘...\n");
if (sync_mapping(mf) == -1) {
fprintf(stderr, "同步失败\n");
}
// 读取并显示文件开头和结尾的数据
printf("\n文件开头内容:\n%s", (char *)mf->addr);
if (mf->size > 100) {
printf("\n文件末尾内容:\n%s\n", (char *)mf->addr + mf->size - 100);
}
// 清理
printf("清理资源...\n");
if (unmap_file(mf) == -1) {
fprintf(stderr, "取消映射失败\n");
}
printf("完成!\n");
return 0;
}
- 完整的内存映射工具函数
# 编译
gcc -o mmap_example mmap_example.c
# 运行
./mmap_example
- 关键函数说明
mmap() - 创建内存映射
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
munmap() - 取消内存映射
int munmap(void *addr, size_t length);
msync() - 同步内存到磁盘
int msync(void *addr, size_t length, int flags);
- 注意事项
-
权限设置:
- PROT_READ - 可读
- PROT_WRITE - 可写
- PROT_EXEC - 可执行
- PROT_NONE - 不可访问
-
映射类型:
- MAP_SHARED - 共享映射(修改会写回文件)
- MAP_PRIVATE - 私有映射(写时复制)
- MAP_ANONYMOUS - 匿名映射(不关联文件)
-
错误处理:
- 检查返回值是否为 MAP_FAILED
- 使用 perror() 输出错误信息
-
性能考虑:
-
适合大文件操作
-
减少系统调用次数
-
注意内存对齐和页面大小
这个实现提供了内存映射的基本功能,可以根据具体需求进行扩展和优化。

浙公网安备 33010602011771号