5分钟学会两年经验Linux运维都不懂的内核问题
我们先来看下 tmpfs ,tmpfs 和 procfs,sysfs 以及 ramfs 一样,都是基于内存的文件系统,tmpfs 和 ramfs 的区别就是 ramfs 的文件基于纯内存的,和 tmpfs 除了纯内存外,还会使用 swap 交换空间,以及 ramfs 可能会把内存耗尽,而 tmpfs 可以限定使用内存大小,可以用命令 df -T -h 查看系统一些文件系统,其中就有一些是 tmpfs,比较出名的是目录 /dev/shm tmpfs 文件系统源文件在内核源码 mm/shmem.c,tmpfs实现很复杂,之前有介绍虚拟文件系统,基于 tmpfs 文件系统创建文件和其他基于磁盘的文件系统一样,也会有 inode,super_block,identry,file 等结构,区别主要是在读写上,因为读写才涉及到文件的载体是内存还是磁盘。 而 tmpfs 文件的读函数 shmem_file_read,过程主要为通过 inode 结构找到 address_space 地址空间,其实就是磁盘文件的 pagecache,然后通过读偏移定位cache 页以及页内偏移。 这时就可以直接从这个 pagecache 通过函数 __copy_to_user 将缓存页内数据拷贝到用户空间,当我们要读物的数据不pagecache中时,这时要判断是否在 swap 中,如果在则先将内存页 swap in,再读取。 tmpfs 文件的写函数 shmem_file_write,过程主要为先判断要写的页是否在内存中,如果在,则直接将用户态数据通过函数__copy_from_user拷贝至内核pagecache中覆盖老数据,并标为 dirty。 如果要写的数据不再内存中,则判断是否在swap 中,如果在,则先读取出来,用新数据覆盖老数据并标为脏,如果即不在内存也不在磁盘,则新生成一个 pagecache 存储用户数据。 由上面分析,我们知道基于 tmpfs 的文件也是使用 cache 的,我们可以在/dev/shm上创建一个文件来检测下: 看到了吧,cache 增长了1G,验证了 tmpfs 的确使用的 cache 内存。 其实 mmap 匿名映射原理也是用了 tmpfs,在 mm/mmap.c->do_mmap_pgoff 函数内部,有判断如果 file 结构为空以及为 SHARED 映射,则调用 shmem_zero_setup(vma) 函数在 tmpfs 上用新建一个文件 这里就解释了为什么共享匿名映射内存初始化为0了,但是我们知道用 mmap 分配的内存初始化为0,就是说 mmap 私有匿名映射也为0,那么体现在哪了? 这个在 do_mmap_pgoff 函数内部可没有体现出来,而是在缺页异常,然后分配一种特殊的初始化为0的页。 那么这个 tmpfs 占有的内存页可以回收吗? 也就是说 tmpfs 文件占有的 pagecache 是不能回收的,道理也很明显,因为有文件引用这些页,就不能回收。 4.3 共享内存 posix 共享内存其实和 mmap 共享映射是同一个道理,都是利用在 tmpfs 文件系统上新建一个文件,然后再映射到用户态,最后两个进程操作同一个物理内存,那么 System V 共享内存是否也是利用 tmpfs 文件系统了? 我们可以跟踪到下述函数 这个函数就是新建一个共享内存段,其中函数 shmem_kernel_file_setup 就是在 tmpfs 文件系统上创建一个文件,然后通过这个内存文件实现进程通信,这我就不写测试程序了,而且这也是不能回收的,因为共享内存ipc机制生命周期是随内核的,也就是说你创建共享内存之后,如果不显示删除的话,进程退出之后,共享内存还是存在的。 之前看了一些技术博客,说到 Poxic 和 System V 两套 ipc 机制(消息队列,信号量以及共享内存)都是使用 tmpfs 文件系统,也就是说最终内存使用的都是 pagecache,但是我在源码中看出了两个共享内存是基于 tmpfs 文件系统,其他信号量和消息队列还没看出来(有待后续考究)。 (编辑:源码门户网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |