如何使用mmap在堆中分配内存?

dom*_*lao 12 c heap memory-management mmap

只是问题陈述,我如何使用mmap()在堆中分配内存?这是我唯一的选择,因为malloc()它不是可重入的函数.

R..*_*R.. 23

你为什么需要重入?唯一需要的是从信号处理程序调用函数; 否则,线程安全性也一样好.这两个mallocmmap是线程安全的.每个POSIX都不是异步信号安全的.实际上,mmap从信号处理程序可能工作正常,但从信号处理程序分配内存的整个想法是一个非常糟糕的主意.

如果你想用来mmap分配匿名内存,你可以使用(不是100%便携但绝对是最好的):

p = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
Run Code Online (Sandbox Code Playgroud)

便携但丑陋的版本是:

int fd = open("/dev/zero", O_RDWR);
p = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
close(fd);
Run Code Online (Sandbox Code Playgroud)

请注意MAP_FAILED,不是NULL,失败的代码.

  • 然后没有一致的方式来分配内存,但`mmap`将"可能"起作用.修复设计需要从信号处理程序分配内存会好得多.通常,信号处理程序应该不执行任何操作,或者只设置单个标志变量或将字节写入管道. (4认同)
  • 顺便说一下,由于"什么都不做"可能不清楚,"无所事事"信号处理程序很有用,省略了`SA_RESTART`标志来中断系统调用.设置一个do-nothing信号处理程序来中断系统调用并使用`pthread_kill`将信号发送到特定线程是一种"滚动你自己的"线程取消的方法,而没有不可修复的资源泄漏问题`pthread_cancel`导致.如果您设置定时器/闹钟以生成信号,设置系统调用的超时,它对于单个线程也很有用. (3认同)
  • `MAP_PRIVATE`对通过`shm_open`获得的共享内存有效吗?我想是的,因为我无法找到它被明确禁止的任何地方,但这似乎是违反直觉的. (3认同)
  • 只需将大小存储在`mmap`分配块的开头,然后返回指向存储大小的字节后面的指针.然后释放块就像备份读取大小并将新指针和大小传递给`munmap`一样简单. (3认同)
  • 最便携的版本可能不是打开`/ dev/zero`而是使用`shm_open`,它在内部做同样的事情,但不要求你的文件系统有特殊文件. (2认同)
  • @sasayins:不是那样的.你必须将映射的长度传递给`munmap`; 你不能只通过0. (2认同)

Dig*_*oss 9

制作一个简单的slab分配器


尽管在信号处理程序1中分配内存看起来确实是最好避免的,但它当然可以完成.

不,你不能直接使用malloc().如果你想让它在堆中,那么mmap也不会工作.

我的建议是你制作一个基于malloc 的专用slab分配器.

确切地确定所需对象的大小,并预先分配一些对象.最初使用malloc()分配它们并保存它们以便以后同时使用.您可以使用本质上可重入的队列和取消队列函数来获取和释放这些块.如果它们只需要从信号处理程序进行管理,那么即使这样也没有必要.

问题解决了!


1.如果你没有这样做,那么你似乎有一个嵌入式系统或者只能使用malloc().