我在Linux 2.6.我有一个环境,其中2个进程通过简单的消息传递模式实现模拟(使用共享内存)数据交换.
我有一个客户端进程(从父服务器分叉,它是服务器),它将结构(消息)写入创建的内存映射区域(在fork之后):
message *m = mmap(NULL, sizeof(message), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)
然后,该指针被写入到队列(在链接列表的形式)转换成是共同的服务器和客户端处理(因为如果事先创建上面相同的代码叉)另一个共享存储器区域.然后由服务器读取该区域,该服务器获得指向消息的指针并对其进行处理.
问题是*m是在fork()之后创建的,当服务器进程尝试访问指向的内存位置时,我得到了分段错误.在客户端创建后,是否可以将该内存区域附加到服务器POST分叉?
注意:我不想在分叉之前将指针映射到消息(然后在服务器之前共享它)因为我通常不知道客户端想要发送到服务器的消息数量,而且可能还有更多消息比一个客户端进程,所以我想只在客户端需要发送消息时创建一个新的共享内存块,并在服务器收到该消息后取消映射.
注意:这是出于学术目的:我知道这不是解决这个问题的最佳方法,但我只需要遵循这条道路.
提前致谢!
我有以下与处理文件和映射它们相关的问题(mmap):
mmap然后写入该文件到内存?mmap- ,,PROT_NONE 使用文件,那么相同的保护级别也可以实现.,等等.那么,为什么?PROT_READPROT_WRITEO_RDONLYO_RDWRmmapmmap有一个文件到内存,如果我们写入mmap返回的内存位置,它是否也同时写入该文件?请帮我回复所有问题.
非常感谢提前.
*编辑:在线程之间共享文件*
据我所知,如果我们在两个线程(非进程)之间共享一个文件,那么建议将mmap它放入内存然后使用它,而不是直接使用该文件.
但我们知道使用文件意味着它肯定在主内存中,那么为什么线程需要再次进行mmaped?
众所周知:http://linux.die.net/man/3/malloc
默认情况下,Linux遵循乐观的内存分配策略.这意味着当malloc()返回非NULL时,无法保证内存确实可用.如果事实证明系统内存不足,那么一个或多个进程将被OOM杀手杀死.
和我们能够成功地通过使用分配1个拍字节VMA(虚拟存储区)的malloc(petabyte);:http://ideone.com/1yskmB
#include <stdio.h>
#include <stdlib.h>
int main(void) {
long long int petabyte = 1024LL * 1024LL * 1024LL * 1024LL * 1024LL; // 2^50
printf("petabyte %lld \n", petabyte);
volatile char *ptr = (volatile char *)malloc(petabyte);
printf("malloc() - success, ptr = %p \n", ptr);
ptr[petabyte - 1LL] = 10;
printf("ptr[petabyte - 1] = 10; - success \n");
printf("ptr[petabyte - 1] = %d \n", (int)(ptr[petabyte - 1LL]));
free((void*)ptr); // why the error is here? …Run Code Online (Sandbox Code Playgroud) 给定一个通过mmap'd文件创建大型linux内核页面缓存的进程,在具有内存限制的docker容器(cgroup)中运行会导致内核slab分配错误:
Jul 18 21:29:01 ip-10-10-17-135 kernel: [186998.252395] SLUB: Unable to allocate memory on node -1 (gfp=0x2080020)
Jul 18 21:29:01 ip-10-10-17-135 kernel: [186998.252402] cache: kmalloc-2048(2412:6c2c4ef2026a77599d279450517cb061545fa963ff9faab731daab2a1f672915), object size: 2048, buffer size: 2048, default order: 3, min order: 0
Jul 18 21:29:01 ip-10-10-17-135 kernel: [186998.252407] node 0: slabs: 135, objs: 1950, free: 64
Jul 18 21:29:01 ip-10-10-17-135 kernel: [186998.252409] node 1: slabs: 130, objs: 1716, free: 0
Run Code Online (Sandbox Code Playgroud)
看着slabtop我可以看到在以内存限制开始的容器中,buffer_head,radix_tree_node和kmalloc *对象的数量受到严格限制。这似乎会对应用程序中的IO吞吐量产生病理影响,并且可以通过观察到iostat。即使页面缓存消耗了在容器外部运行的主机OS上的所有可用内存或没有内存限制的容器,也不会发生这种情况。
这似乎是内核内存记帐中的一个问题,其中不将内核页面高速缓存计入容器内存,而是将其支持的SLAB对象计入容器内存。该行为似乎是异常的,因为在预先分配了一个大的平板对象池时运行,内存受限的容器运行良好,可以自由地重用现有的平板空间。只有在容器中分配的平板才计入容器。内存和内核内存的容器选项的组合似乎无法解决此问题(除非根本不设置内存限制,或者设置的限制太大以至于不能限制平板,但这会限制可寻址空间)。我试图通过cgroup.memory=nokmem引导完全禁用kmem记帐,但没有成功。
系统信息:
我有一个非常大的文件,我正试图用mmap打开,并且它允许我被拒绝.我尝试了不同的旗帜和模式,os.open但它不适合我.
我究竟做错了什么?
>>> import os,mmap
>>> mfd = os.open('BigFile', 0)
>>> mfile = mmap.mmap(mfd, 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
mmap.error: [Errno 13] Permission denied
>>>
Run Code Online (Sandbox Code Playgroud)
(使用内置的open()工作通过python docs示例,但它似乎在读取和写入模式下打开文件的多个句柄.我需要的mmap.mmap方法是文件编号,所以我不认为我需要创建一个file对象;因此我尝试使用os.open())
我对使用内存映射IO的前景感兴趣,最好利用boost :: interprocess中的工具来实现跨平台支持,将文件中不连续的系统页大小块映射到内存中的连续地址空间.
简化的具体方案:
我有许多"普通旧数据"结构,每个都有一个固定的长度(小于系统页面大小.)这些结构被连接成一个(非常长的)流,其结构的类型和位置由在流中进行它们的那些结构的值.我的目标是在要求苛刻的并发环境中最小化延迟并最大化吞吐量.
我可以非常有效地读取这些数据,通过内存映射它至少是系统页面大小的两倍...并建立一个新的映射,立即读取超出倒数第二个系统页面边界的结构.这使得与普通老式的数据结构交互的代码是一无所知,这些结构是存储器映射...,例如,可以比较使用memcmp()直接在两个不同的结构,而不必关心页边界.
事情变得有趣的是关于更新这些数据流......当它们被(同时)读取时.我想要使用的策略受到系统页面大小粒度的"写入时复制"的启发......基本上是写"覆盖页面" - 允许一个进程读取旧数据而另一个进程读取更新数据.
管理哪些叠加页面以及何时使用不一定是微不足道的......这不是我主要关注的问题.我主要担心的是我可能有一个跨越第4页和第5页的结构,然后更新完全包含在第5页的结构...在第6位写入新页面...当第5页时,将第5页保留为"垃圾收集"决定不再可达.这意味着,如果我将第4页映射到位置M,我需要将第6页映射到内存位置M + page_size ...,以便能够使用现有的(非内存映射)可靠地处理跨页边界的结构意识到)功能.
我正在努力建立最好的策略,而且我受到文件的阻碍,我认为这是不完整的.本质上,我需要将地址空间的分配与内存映射分离到该地址空间.使用mmap(),我知道我可以使用MAP_FIXED - 如果我希望显式控制映射位置......但我不清楚我应该如何保留地址空间以便安全地执行此操作.我可以在没有MAP_FIXED的情况下映射/ dev/zero两个页面,然后使用MAP_FIXED两次将两个页面映射到显式VM地址的分配空间吗?如果是这样,我应该三次打电话给munmap()吗?它会泄漏资源和/或有任何其他不利的开销吗?为了使问题更加复杂,我想在Windows上采用类似的行为......有什么办法可以做到这一点吗?如果我要牺牲我的跨平台野心,是否有完整的解决方案?
-
感谢您的回答,Mahmoud ......我已经读过了,并且认为我已经理解了代码......我已经在Linux下编译了它,它的行为与您的建议一致.
我主要关心的是第62行 - 使用MAP_FIXED.它对mmap做了一些假设,当我阅读我能找到的文档时,我无法确认.您将"更新"页面映射到与最初返回的mmap()相同的地址空间 - 我认为这是'正确' - 即不是恰好在Linux上运行的东西?我还需要假设它适用于文件映射和匿名映射的跨平台.
这个样本肯定让我前进......记录我最终需要的东西可能是在Linux上用mmap()实现的 - 至少.我真正喜欢的是指向文档的指针,该文档显示MAP_FIXED行将在示例演示中运行...并且,理想情况下,从Linux/Unix特定mmap()到独立平台的转换(Boost :: interprocess) )方法.
做的有什么好处:shm_open跟着一个mmap?
为什么不创建一个常规文件,然后将其传递fd给mmap?
我看不到它的优点shm_open- 这些只是参考,不是吗?
我读过全家人.在我看来,"秘密"在于mmaping动作 - 文件"类型"似乎毫无意义.
任何指针都会很好,尤其是性能帐户.
我的上下文是一个(循环可写的)缓冲区(比如128MB),它将被不断地写成一个进程,并且不断地从另一个进程转发.
举个例子:这个 open/mmap方法有什么问题.
编辑
准确地说,下面的一个比另一个更好:
fd = open("/dev/shm/myshm.file", O_CREAT|O_RDWR, S_IRUSR | S_IWUSR);
mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
Run Code Online (Sandbox Code Playgroud)
与
fd = shm_open("/myshm.file", O_RDWR|O_CREATE, S_IRUSR | S_IWUSR);
mem = mmap(...same as before...);
Run Code Online (Sandbox Code Playgroud)
当我在fs open下创建一个带有常规文件的文件/dev/shm,并向其转储了一堆垃圾时,我的可用内存下降了1G,我的可用磁盘空间保持不变.
这两种方法有什么区别?
从man页面,
MAP_ANONYMOUS
The mapping is not backed by any file; its contents are initialized to zero. The fd and offset arguments are ignored; however, some implementations require
fd to be -1 if MAP_ANONYMOUS (or MAP_ANON) is specified, and portable applications should ensure this. The use of MAP_ANONYMOUS in conjunction with
MAP_SHARED is only supported on Linux since kernel 2.4.
Run Code Online (Sandbox Code Playgroud)
使用目的是MAP_ANONYMOUS什么?任何一个例子都会很好.还要从哪里映射内存?
在man页面上写的The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux …
如果我创建mmap(2)一个文件用prot的参数,PROT_READ只和文件支持它也是只读的,没有变化,有没有之间的性能差异(或根本任何区别)MAP_SHARED和MAP_PRIVATE?内核会在两者之间做些不同的事吗?
(文档仅指"更新"方面的行为差异,但因为它PROT_READ不存在更新.我想知道是否还有其他差异?)
c代码:
// program break mechanism
// TLPI exercise 7-1
#include <stdio.h>
#include <stdlib.h>
void program_break_test() {
printf("%10p\n", sbrk(0));
char *bl = malloc(1024 * 1024);
printf("%x\n", sbrk(0));
free(bl);
printf("%x\n", sbrk(0));
}
int main(int argc, char **argv) {
program_break_test();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译以下代码时:
printf("%10p\n", sbrk(0));
Run Code Online (Sandbox Code Playgroud)
我收到警告提示:
format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’
问题1:为什么?
在我之后malloc(1024 * 1024),程序突破似乎没有改变.
这是输出:
9b12000
9b12000
9b12000
Run Code Online (Sandbox Code Playgroud)
问题2:进程在启动以备将来使用时是否在堆上分配内存?或者编译器改变分配的时间点?否则,为什么?
[更新]摘要:brk()或mmap()
在查看TLPI并检查手册页(在TLPI的作者的帮助下)之后,现在我了解了如何malloc()决定使用brk()或mmap(),如下所示:
mallopt() …