暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

关于Linux共享内存的实验(二)

术道经纬 2020-07-27
2914

上文的实验中,我们创建了一段共享内存,接下来看看如何才能彻底释放它。因为这段共享内存是作为"/dev/shm"文件系统中的一个文件存在的,如果直接用"rm"命令删掉这个文件会怎样呢?

rm dev/shm/shm1

删除很顺利,并没有因为还有进程(就是我们的测试程序)在使用这段共享内存,就不可以删除这个文件。但是,再用之前的命令走一波:

"/dev/shm"下确实没有"shm1"这个文件了,"du -h"显示的文件系统大小也降下来了,可是其他几项反应内存占用情况的数值,都几乎纹丝不动啊,而且"df"和"du"的输出结果居然是不一致的。

这个时候再用"lsof dev/shm"命令扫一下,可以看到"shm1"这个文件被标记为了"deleted"的状态,因为lsof(list open files)是列出所有打开的文件,而"shm1"这个文件并没有被正确的close,所以还是会显示在lsof的输出结果中。

看来直接粗暴地删掉代表共享内存的文件是不行的,那……更粗暴地直接杀掉进程呢?重新做一下这个实验,不删掉文件,只kill掉正在运行的测试程序,看下结果如何:

"Mapped"的值减小了256MiB,这个不难理解,因为上文说过,"Mapped"本身就是代表映射后被进程所使用的内存,现在进程都挂掉了,也就不会再使用内存了。进程消亡,进程页表自然也就被内核回收了,所以"PageTables"的值也回到了之前的状态。

可是"Used"和"Shmem"这两项的值还是巍然不动。而且这个时候用lsof检测已经看不出异常了。

单独删掉文件和单独杀掉进程都不行,那双管齐下呢?来看下结果吧:

嗯,一切终于都回到了最初的状态。那为什么测试结果是这样的呢?

这是因为在POSIX文件系统中,当创建一个文件的时候,会生成一个标识文件的inode,同时还会生成一个路径(目录),路径是为了方便查找inode的,一个路径就相当于一个"link",因此初始的时候这个inode的link count为1。当一个进程试图用"路径+文件名"打开一个文件时,内核查找这个路径(link),找到文件对应的inode,返回指向(refer to)这个inode的文件描述符fd,之后进程就通过这个文件描述符来访问文件,路径就不再需要了。

当使用"rm /dev/shm/shm1"命令的时候,目标文件"shm1"并没有被真正地删除,删除的只是"/dev/shm/shm1"这个路径。此时,内核将inode的link count减1,但不一定会删除inode,因为删除inode需要同时满足两个条件:

  • inode的link count为0,文件处于"unlink"的状态。

  • 没有再指向这个inode的文件描述符。

所以单独用rm命令"删除"文件,只满足了第一个条件,而通过unmmap()或者结束进程,文件描述符会被释放,只满足第二个条件。正确的做法应该是在进程退出之前,调用shm_unlink(),这样既可以close掉文件,又可以让link count减1。

shm_unlink("shm1");

还有一个问题,为什么使用rm命令移除目录后,"df"和"du"命令的显示结果会出现差异?因为"df"命令是通过查询文件系统的空闲块来计算其占用的存储空间,而"du"命令是通过查询文件系统的目录来统计其大小。

因此对于unlink的文件,虽然还在占用磁盘空间,但由于其目录已经不存在,所以无法被du识别到,可见du命令的输出结果并不能作为判断文件系统大小的依据。


文章转载自术道经纬,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论