文章目录
文章来源:https://www.kernel.org/doc/html/latest/filesystems/tmpfs.html
一、简介
Tmpfs是一种文件系统,它将所有文件保存在虚拟内存中。
Tmpfs,以前称为shmfs,是一个临时文件系统,指的是位于内存和/或交换分区中的文件系统。Tmpfs不会将文件数据存储在正常的非易失性存储器上。相反,UNIX内核管理虚拟内存,这是Tmpfs文件所在的位置。创建Tmpfs的主要原因是通过允许在不使用磁盘或网络I/O的情况下写入和读取临时文件来提高性能。
在tmpfs中,所有内容都是临时的,这意味着不会在硬盘上创建任何文件。如果卸载tmpfs实例,其中存储的所有内容都将丢失。
tmpfs将所有内容放入内核内部缓存,并根据其包含的文件的大小而增长或缩小,并且如果为tmpfs挂载启用了交换空间,它可以将不需要的页面交换到交换空间中。tmpfs还支持透明大页(Transparent Huge Pages,THP)。这些功能使得tmpfs非常适合存储临时数据,如临时文件、缓存和临时存储等。
在 tmpfs 存放的文件是动态占用内存空间的,随着文件占用空间的增大而增大文件系统,文件被删除时,动态地减小文件系统空间并释放内存。这一切都是 tmpf 自动处理的。
tmpfs是在ramfs的基础上进行扩展的,具有一些可以由用户空间配置的选项,下面进一步列出并解释了其中的一些选项,其中一些选项可以通过重新挂载(‘mount -o remount …’)文件系统时进行动态重新配置。tmpfs文件系统可以调整大小,但不能调整到低于当前使用量的大小。tmpfs还支持POSIX ACL(访问控制列表)和trusted.、security.、user.*命名空间的扩展属性。ramfs不使用交换空间,并且您无法修改ramfs文件系统的任何参数。ramfs文件系统的大小限制取决于可用的内存量,因此在使用时必须小心,以免耗尽内存。
换句话说,tmpfs在ramfs的基础上提供了更多的功能和配置选项。与ramfs相比,tmpfs可以动态地调整大小、支持POSIX ACL和扩展属性,并且允许在运行时重新配置。另外,tmpfs还可以使用交换空间以便在内存不足时进行页面交换,而ramfs则完全存储在内存中,没有交换的能力。
tmpfs和ramfs的另一种选择是使用brd创建RAM磁盘(/dev/RAM*),这允许您在物理RAM中模拟块设备磁盘。要写入数据,您只需要在这个ramdisk上创建一个常规文件系统。与ramfs一样,brd-ramdisks无法交换。brd-ramdisk在初始化时也配置了大小,您无法动态调整它们的大小。与brd-ramdisks相反,tmpfs有自己的文件系统,它根本不依赖于块层。
由于tmpfs完全存在于页面缓存中,并可以选择使用交换空间,所有tmpfs页面将显示为/proc/meminfo中的"Shmem"和free(1)中的"Shared"。请注意,这些计数器还包括共享内存(shmem,参见ipcs(1))。获取计数的最可靠方法是使用df(1)和du(1)命令。
在/tmpfs上运行的进程使用的内存页面将被列为"Shmem",这是因为内核将tmpfs页面视为共享内存的一部分。因此,在/proc/meminfo中,"Shmem"计数器将包括tmpfs页面以及其他共享内存的页面。
要获取tmpfs使用的实际磁盘空间,可以使用df(1)命令。它将显示挂载的tmpfs文件系统的大小和使用情况。
要获取tmpfs中的文件和目录的大小,可以使用du(1)命令。它将递归地计算指定路径中的文件和目录的大小。
tmpfs有以下用途:
(1)内核始终会有一个不可见的内部挂载点,用于共享的匿名映射和SYSV共享内存。
这个挂载点不依赖于CONFIG_TMPFS选项。即使未设置CONFIG_TMPFS,tmpfs的用户可见部分也不会构建。但是内部机制始终存在。
System V 共享内存是早期 Unix 系统引入的一种 IPC 机制,它使用了 shmget、shmat、shmdt 和 shmctl 等系统调用来创建和管理共享内存段。
在 System V 共享内存中,共享内存段由一个唯一的标识符(shmid)来标识,并可以通过该标识符在不同的进程之间进行访问。
(2)glibc 2.2及以上版本期望将tmpfs挂载在/dev/shm上,用于POSIX共享内存(shm_open、shm_unlink)。将以下行添加到/etc/fstab中可以实现这一点:
tmpfs /dev/shm tmpfs defaults 0 0
glibc为了实现POSIX共享内存,需要将一个tmpfs挂载到/dev/shm这个路径下。
如果需要,记得创建你打算挂载tmpfs的目录。
Posix 共享内存是在 POSIX 标准中引入的共享内存机制,它使用了 shm_open、shm_unlink、mmap 和 munmap 等函数来创建和管理共享内存。
在 Posix 共享内存中,共享内存段由一个命名对象(名字)来标识,可以通过该名字在不同的进程之间进行访问。
对于SYSV共享内存,不需要此挂载点。内部挂载点已用于SYSV共享内存。(在2.3版本的内核中,需要挂载tmpfs的前身(shm fs)才能使用SYSV共享内存)。
(3)有些人认为将tmpfs挂载在例如/tmp和/var/tmp上,并使用一个大的交换分区非常方便。现在,tmpfs文件的循环挂载也可以正常工作,因此大多数发行版提供的mkinitrd应该能成功将tmpfs挂载在/tmp上。
无论是POSIX共享内存、System V共享内存还是共享匿名映射都是建立在tmpfs的基础上的。
POSIX共享内存与System V 共享内存在内核都是通过tmpfs实现,但对应两个不同的tmpfs实例,相互独立。
通过/proc/sys/kernel/shmmax可以限制System V 共享内存(单个)的最大值,通过/dev/shm可以限制POSIX共享内存的最大值(所有之和)。
二、挂载选项
2.1 size mount options
tmpfs有三个挂载选项用于设置大小:
mount options | description |
---|---|
size | 该选项用于设置为tmpfs实例分配的字节数上限。默认值为物理RAM的一半,不包括交换空间。如果你过度分配tmpfs实例的大小,系统可能会因为OOM(Out of Memory)处理程序无法释放该内存而导致死锁。 |
nr_blocks | 该选项与size相同,但以PAGE_SIZE大小的块为单位进行设置。 |
nr_inodes | 该选项用于设置该实例的最大inode数。默认值为物理RAM页数的一半,或者(在具有高内存的机器上)低内存RAM页数的数量,以较小值为准。 |
# free -m
total used free shared buff/cache available
Mem: 681 155 385 21 140 277
Swap: 1671 85 1586
# df -Th
文件系统 类型 容量 已用 可用 已用% 挂载点
......
tmpfs tmpfs 341M 0 341M 0% /tmp
......
可以看到tmpfs实例分配的字节数默认值为物理RAM的一半,不包括交换空间。
这些参数接受后缀k、m或g,用于表示千字节、兆字节和吉字节,并且可以在重新挂载时进行更改。size参数还接受后缀%,以将该tmpfs实例的大小限制为物理RAM的百分比。当未指定size和nr_blocks时,默认值为size=50%。
如果nr_blocks=0(或size=0),则该实例中的块大小不受限制;如果nr_inodes=0,则inode数不受限制。通常不建议使用这样的选项进行挂载,因为它允许具有写访问权限的任何用户使用机器上的所有内存;但它能够增强在具有许多CPU并对其进行密集使用的系统中该实例的可伸缩性。
如果nr_inodes不为0,则限制的inodes空间也会被扩展属性使用:使用"df -i"命令时,IUsed和IUse%会增加,而IFree会减少。
2.2 swap mount option
tmpfs的块可能会在内存不足时被换出(swap)。tmpfs有一个挂载选项可以禁用其对交换空间的使用:
mount option | description |
---|---|
noswap | 禁用交换空间。重新挂载时必须遵守原始设置。默认情况下,交换空间是启用的。 |
2.3 Transparent Huge Pages mount options
tmpfs还支持透明大页面(Transparent Huge Pages),这需要一个配置了CONFIG_TRANSPARENT_HUGEPAGE且对你的系统支持大页面(具体取决于架构)的内核。用于此功能的挂载选项包括:
mount options | description |
---|---|
huge=never | 不分配大页面。这是默认选项。 |
huge=always | 每次需要新页面时尝试分配大页面。 |
huge=within_size | 仅在大页面完全位于i_size范围内时分配。还会考虑madvise(2)的提示。 |
huge=advise | 仅在使用madvise(2)请求时分配大页面。 |
通过使用这些挂载选项,可以控制tmpfs实例是否使用透明大页面。透明大页面是一种优化技术,通过使用更大的页面来减少页表的数量,提高内存访问效率。根据应用程序的需求和系统的支持情况,可以选择合适的选项来优化tmpfs的性能。 |
另请参阅Transparent Hugepage Support,其中描述了sysfs文件/sys/kernel/mm/Transparent_Hugepage/shm_enabled:该文件可用于在紧急情况下拒绝所有tmpfs装载上的巨大页面,或强制所有tmpfs安装上的巨大页页进行测试。
# cat /sys/kernel/mm/transparent_hugepage/shmem_enabled
always within_size advise [never] deny force
2.4 quota mount options
tmpfs也支持配额(quota),具有以下挂载选项:
mount options | description |
---|---|
quota | 启用挂载点上的用户和组配额计算和执行。Tmpfs使用隐藏的系统配额文件,在挂载时进行初始化。 |
usrquota | 启用挂载点上的用户配额计算和执行。 |
grpquota | 启用挂载点上的组配额计算和执行。 |
usrquota_block_hardlimit | 设置全局用户配额块硬限制。 |
usrquota_inode_hardlimit | 设置全局用户配额inode硬限制。 |
grpquota_block_hardlimit | 设置全局组配额块硬限制。 |
grpquota_inode_hardlimit | 设置全局组配额inode硬限制。 |
所有与配额相关的挂载选项都不能在重新挂载时设置或更改。
配额限制参数接受后缀k、m或g,用于表示千字节、兆字节和吉字节,并且不能在重新挂载时更改。默认的全局配额限制会在第一次访问用户/组/项目的配额条目时生效,对于除root之外的任何用户/组/项目都适用。换句话说,在挂载后创建具有特定id所有权的inode时,配额限制不会初始化为零,而是使用挂载选项提供的特定值进行初始化。这意味着可以随时更改任何用户/组id的限制,与通常情况下可以更改的限制一样。
请注意,tmpfs配额不支持用户命名空间(user namespaces),因此如果在用户命名空间内启用了配额,则不会进行uid/gid转换。
配额功能允许对tmpfs挂载点上的用户和组进行限制和管理,以控制其使用的空间和inode数量。这对于资源管理和保护系统免受滥用非常有用。
三、Tmpfs的使用
/dev/shm 是一个特殊的目录,用于在内存中创建临时文件系统。该目录提供了一种在进程之间共享内存的机制,因为在内存中进行操作比在磁盘上进行操作更快。
/dev/shm 目录通常用于临时存储需要快速访问的数据,例如共享内存段、临时文件等。在该目录下创建的文件将直接映射到系统的共享内存中。
要使用 /dev/shm 目录,可以像使用任何其他目录一样进行文件操作。可以使用命令行工具(如cp、mv、rm)或编程语言(如C、C++、Python)来读取、写入或删除文件。
# df -h
......
tmpfs 3.8G 0 3.8G 0% /dev/shm
......
查看内存情况:
# free -m
total used free shared buff/cache available
Mem: 7697 448 6999 10 248 7003
Swap: 2047 0 2047
在/dev/shm 目录下创建一个1GB的文件:
/dev/shm# dd if=/dev/zero of=1.txt bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.267171 s, 4.0 GB/s
/dev/shm# df -h
Filesystem Size Used Avail Use% Mounted on
tmpfs 3.8G 1.0G 2.8G 27% /dev/shm
查看内存情况:
# free -m
total used free shared buff/cache available
Mem: 7697 454 5968 1034 1273 5972
Swap: 2047 0 2047
可以看到在/dev/shm 目录下创建一个1GB大小的文件后,查看缓存使用情况,buff/cache:从248到1273,刚好使用1GB的缓存。
tmpfs 使用的 是cache 内存。
使用sync和/proc/sys/vm/drop_caches文件情况缓存:
sync; echo 1 > /proc/sys/vm/drop_caches
先执行 sync 命令将数据同步写入磁盘,确保数据已保存,然后使用 echo 命令将值 1 写入 /proc/sys/vm/drop_caches 文件,以清除页缓存。
/proc/sys/vm/drop_caches (since Linux 2.6.16)
Writing to this file causes the kernel to drop clean caches, dentries, and inodes from memory, causing that memory to become free. This can be useful for memory
management testing and performing reproducible filesystem benchmarks. Because writing to this file causes the benefits of caching to be lost, it can degrade
overall system performance.
To free pagecache, use:
echo 1 > /proc/sys/vm/drop_caches
To free dentries and inodes, use:
echo 2 > /proc/sys/vm/drop_caches
To free pagecache, dentries and inodes, use:
echo 3 > /proc/sys/vm/drop_caches
Because writing to this file is a nondestructive operation and dirty objects are not freeable, the user should run sync(1) first.
# free -m
total used free shared buff/cache available
Mem: 7697 446 5977 1034 1273 5980
Swap: 2047 0 2047
可以看到 buff/cache 没有变化。
我们删除创建的文件:
/dev/shm# rm -rf 1.txt
/dev/shm# df -h
Filesystem Size Used Avail Use% Mounted on
tmpfs 3.8G 0 3.8G 0% /dev/shm
查看内存使用情况:
# free -m
total used free shared buff/cache available
Mem: 7697 447 7001 10 248 7004
Swap: 2047 0 2047
buff/cache:从1273到248,刚好释放了1GB的缓存。
因此可以知道 tmpfs 文件占有的 pagecache 是不能回收的,因为有文件引用这些页,就不能回收。
参考资料
https://mp.weixin.qq.com/s/I1fHrRqZnZ7CdudFAmiNog
http://hustcat.github.io/shared-memory-tmpfs/