本文总结了部分Linux中使用的技术及相关函数。

mmap()--Memory Map a File

简介

mmap是一种内存映射文件的方法。即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。

实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用 read(), write()等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。

void *mmap( void *addr, size_t len, int protection, int flags, int fildes, off_t off);   

优缺点

优点
  1. 对文件的读写操作跨过了页缓存,减少了数据拷贝的次数,提高了文件读写的效率。
  2. 实现用户空间和内核空间的高效交互方式。
缺点
  1. 文件如果很小,比如小于 4K 的,比如 128bytes ,由于在内存当中的组织都是按页组织的,将文件调入到内存当中是一个页 4K ,相当于 4096-128=3968bytes 的内存空间浪费掉了。
  2. 文件无法完成拓展,因为mmap到内存的时候,你所能操作的范围就已经确定了,无法增加文件长度。
  3. 提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。

应用场景

  1. 减少一次数据拷贝 - 零拷贝(Zero-Copy)的一种

mmap() + write() 可以减少一次 read() 调用中CPU将内核缓冲区中数据拷贝到用户缓冲区的过程。 1

  • JAVA NIO库中 MappedByteBuffer
  • Kafka 读写数据。
  1. ZGC 多视图映射

ZGC 垃圾回收器将内存中的一个对象映射到 Marked0Marked1Remapped 3个视图中,在同一时刻,对象只能处在一个视图中,便于快速找到各个阶段(视图)的对象,提升回收效率。 2

sendfile

在 Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile(),函数形式如下:

#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

它的前两个参数分别是目的端和源端的文件描述符,后面两个参数是源端的偏移量和复制数据的长度,返回值是实际复制数据的长度。

首先,它可以替代 read()write() 这两个系统调用,这样就可以减少一次系统调用,也就减少了 2 次上下文切换的开销。

应用场景

  1. 零拷贝(Zero-Copy)的一种 1

参考文献

Q.E.D.