mmap(memory map)即内存映射,用于将一个文件或设备映射到进程的地址空间,或者创建匿名的内存映射。
mmap/munmap接口是用户空间的最常用的一个系统调用接口,无论是在用户程序中分配内存、读写大文件,链接动态库文件,还是多进程间共享内存,都可以看到mmap/munmap的身影。
在《一文看懂零拷贝技术》中我们介绍了 零拷贝技术 的原理,而且我们知道 mmap 也是零拷贝技术的一种实现。在本文中,我们主要介绍 mmap 的原理。
共享内存是进程间通信最有用的方式,也是最快的IPC形式。共享内存是说:同一块内存被映射到多个进程的地址空间。但是共享内存并不提供同步机制,因此需要互斥锁或者信号量。使用共享内存唯一需要注意的是:当前如果有进程正在向共享内存写数据,则在写入完成以前,别的进程不应当去读、写共享内存。
前一篇博客说了怎样通过命名管道实现进程间通信,但是要在windows是使用命名管道,需要使用python调研windows api,太麻烦,于是想到是不是可以通过共享内存的方式来实现。查了一下,Python中可以使用mmap模块来实现这一功能。 Python中的mmap模块是通过映射同一个普通文件实现共享内存的。文件被映射到进程地址空间后,进程可以像访问内存一样对文件进行访问。 不过,mmap在linux和windows上的API有些许的不一样,具体细节可以查看mmap的文档。 下面看一个例子: serve
内存映射mmap是Linux内核的一个重要机制,它和虚拟内存管理以及文件IO都有直接的关系,这篇细说一下mmap的一些要点。
https://man7.org/linux/man-pages/man2/mmap.2.html
① brk 系统调用 : 该方式本质是 设置 " 进程数据段 “ 的 结束地址 , 将该 ” 结束地址 " 向 高或低 移动 , 实现堆内存的 扩张或收缩 ;
1.mmap函数 所需头文件:#include<sys/mman.h> 函数原型:void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) 参数: 第一个参数void* addr是映射区的首地址,传NULL,让内核去指定,返回值用来指定映射区的首地址。
共享内存是一个非常有意思的话题,一方面共享内存避免了通讯过程中的内存复制问题,是 Linux IPC 通讯中效率最高的一种。另一方面,因为可以直接对内存甚至其他进程的内存进行修改,利用共享内存可以实现一些常规操作无法做到的奇技淫巧。
mmap 另一个非常重要的特性是:减少内存的拷贝次数。在 linux 系统中,文件的读写操作通常通过 read 和 write 这两个系统调用来实现,这个过程会产生频繁的内存拷贝。比如 read 函数就涉及了 2 次内存拷贝:
几种进程间的通信方式:管道,FIFO,消息队列,他们的共同特点就是通过内核来进行通信(假设POSIX消息队列也是在内核中实现的,因为POSIX标准并没有限定它的实现方式)。向管道,FIFO,消息队列写入数据需要把数据从进程复制到内核,从这些IPC读取数据的时候又需要把数据从内核复制到进程。所以这种IPC方式往往需要2次在进程和内核之间进行数据的复制,即进程间的通信必须借助内核来传递。如下图所示:
一、共享内存简介 共享内存区是最快的IPC形式,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。 即每个进程地址空间都有一个共享存储器的映射区,当这
mmap() 系统调用能够将文件映射到内存空间,然后可以通过读写内存来读写文件。我们先来看看 mmap() 系统调用的用法吧,mmap() 函数的原型如下:
首先 , 创建 " 匿名内存映射 “ , 将 ” 物理内存页 “ 映射到 进程的 ” 用户虚拟地址空间 " 中 ;
mmap/munmap接口是用户空间的最常用的一个系统调用接口,无论是在用户程序中分配内存、读写大文件,链接动态库文件,还是多进程间共享内存,都可以看到mmap/munmap的身影。mmap/munmap函数声明如下:
作者:freeboy1015 来源:http://lib.csdn.net/article/linux/62126 一. mmap系统调用 1. mmap系统调用 mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。 当使用mmap映射文件到进程后,就可以直接操作这段虚拟地址进行文件的读写等操作,不必再调用read,write等系统调用.但需注意,直
本文介绍了Linux系统下共享内存的概念、实现方法以及相关的应用,包括共享内存的读写、同步和调试等方面。
之前有不少读者给笔者留言,希望笔者写一篇文章介绍下 mmap 内存映射相关的知识体系,之所以迟迟没有动笔,是因为 mmap 这个系统调用看上去简单,实际上并不简单,可以说是非常复杂的一个系统调用。
零拷贝是老生常谈的问题啦,大厂非常喜欢问。比如Kafka为什么快,RocketMQ为什么快等,都涉及到零拷贝知识点。最近技术讨论群几个伙伴分享了阿里、虾皮的面试真题,也都涉及到零拷贝。因此本文将跟大家一起来学习零拷贝原理。
mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。如下图所示:
下面以最常用的 read() 和 write() 函数来介绍 Linux 的 I/O 处理流程。
执行该程序,输出mmap方法返回的内存地址,同时使用pmap命令输出该程序执行mmap之前以及之后的内存使用情况。
个人名言:“同一条河里淹死两次的人,是傻子,淹死三次及三次以上的人是超人”。经历过上次悲催的面试,决定沉下心来,好好的补充一下基础知识点。本文是这一系列第一篇:进程间通讯之mmap。
分配 虚拟内存页 : 应用进程 调用 mmap 函数后 , 在 Linux 系统中 创建 " 内存映射 “ 时 , 会在 ” 用户虚拟地址空间 “ 中 , 分配一块 ” 虚拟内存区域 " ;
unix访问文件的传统方法使用open打开他们,如果有多个进程访问一个文件,则每一个进程在再记得地址空间都包含有该文件的副本,这不必要地浪费了存储空间。下面说明了两个进程同时读一个文件的同一页的情形,系统要将该页从磁盘读到高速缓冲区中,每个进程再执行一个内存期内的复制操作将数据从高速缓冲区读到自己的地址空间。
Linux下动态库是通过mmap建立起内存和文件的映射关系。其定义如下void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);,在第一个参数start为NULL的时候系统会随机分配一个地址,我们可以通过示例来看mmap映射地址的流程。
mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现了文件磁盘地址和进程虚拟地址的映射关系。实现映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。如下图所示:
前言: 使用了mlock,会把内存lock在内存中,不会被交换,在一定场景下,可以提高性能。 虚拟化场景下,qemu也可以选择lock住一部分内存,来提高Guest的性能。 下文来分析一下mlock的
随着cpu技术发展,现在大部分移动设备、PC、服务器都已经使用上64bit的CPU,但是关于Linux内核的虚拟内存管理,还停留在历史的用户态与内核态虚拟内存3:1的观念中,导致在解决一些内存问题时存在误解。
Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问。
在上一篇博客 【Linux 内核 内存管理】内存管理系统调用 ④ ( 代码示例 | mmap 创建内存映射 | munmap 删除内存映射 ) 中 , 完成了 进程一 的程序 ,
| 导语 企鹅FM近几个版本的外网Crash出现很多OutOfMemory(以下简称OOM)问题,Crash的堆栈都在Thread::start方法上。该文详细分析了发生原因。 ---- 有两种栈: 出现次数最多的一种,称之为 堆栈A。 java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Out of memory java.lang.Thread.nativeCreate(Native Method)
来源:http://lib.csdn.net/article/linux/62126
本文讲解 Linux 的零拷贝技术,云计算是一门很庞大的技术学科,融合了很多技术,Linux 算是比较基础的技术,所以,学好 Linux 对于云计算的学习会有比较大的帮助。
所谓的内存映射就是把物理内存映射到进程的地址空间之内,这些应用程序就可以直接使用输入输出的地址空间,从而提高读写的效率。Linux提供了mmap()函数,用来映射物理内存。在驱动程序中,应用程序以设备文件为对象,调用mmap()函数,内核进行内存映射的准备工作,生成vm_area_struct结构体,然后调用设备驱动程序中定义的mmap函数。
结合这个图,想想Linux系统编程里用到的Buffered IO、mmap(2)、Direct IO,这些机制怎么和Linux IO栈联系起来呢?上面的图有点复杂,我画一幅简图,把这些机制所在的位置添加进去:
长时间运行的Linux服务器,通常 free 的内存越来越少,让人觉得 Linux 特别能“吃”内存,甚至有人专门做了个网站 LinuxAteMyRam.com解释这个现象。实际上 Linux 内核会尽可能的对访问过的文件进行缓存,来弥补磁盘和内存之间巨大的延迟差距。缓存文件内容的内存就是 Page Cache。
共享内存的优势 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因
由于管道仅仅是将一个进程的读端和另一个进程的写端连通的单通信方法,所以又叫“半双工管道”。在shell中管道用“|”表示。 管道的历史很悠久了。
glibc 提供的 ptmalloc 函数 , FreeBSD 提供的 jemalloc 函数 , Google 提供的 tcmalloc 函数 ,
通过上篇文章 《从内核世界透视 mmap 内存映射的本质(原理篇)》的介绍,我们现在已经非常清楚了 mmap 背后的映射原理以及它的使用方法,其核心就是在进程虚拟内存空间中分配一段虚拟内存出来,然后将这段虚拟内存与磁盘文件映射起来,整个 mmap 系统调用就结束了。
调用 mmap 系统调用 , 先检查 " 偏移 " 是否是 " 内存页大小 " 的 " 整数倍 " , 如果偏移是内存页大小的整数倍 , 则调用 sys_mmap_pgoff 函数 , 继续向下执行 ;
本文我们将进入到内核源码实现中,来看一下虚拟内存分配的过程,在这个过程中,我们还可以亲眼看到前面介绍的 mmap 内存映射原理在内核中具体是如何实现的,下面我们就从 mmap 系统调用的入口处来开始本文的内容:
mmap是linux操作系统提供给用户空间调用的内存映射函数,很多人仅仅只是知道可以通过mmap完成进程间的内存共享和减少用户态到内核态的数据拷贝次数,但是并没有深入理解mmap在操作系统内部是如何实现的,原理是什么。
领取专属 10元无门槛券
手把手带您无忧上云