我发现我可以创建一个共享内存对象,并使用 给它表面上的任何大小ftruncate
,而不管我的系统上的资源限制如何。下面的代码将大小设置为 262 TB,并且确实stat()
报告了该大小。然而,262 TB 大于我的/dev/shm
安装,而且我的系统上绝对没有 262 TB 的内存或交换可用。我预计会出现 OOM 错误,但我没有看到系统内存使用量发生显着变化。
这里发生了什么?为什么ftruncate
超出系统资源限制的大小会成功?我假设ftruncate
共享内存对象(或者更一般地说,与 tmpfs)之间存在一些特殊的交互。
import os
import _posixshmem
try:
fd = _posixshmem.shm_open("test", os.O_CREAT | os.O_EXCL | os.O_RDWR, mode=0o600)
os.ftruncate(fd, 52428800 * 5000000)
print(os.stat(fd))
finally:
_posixshmem.shm_unlink("test")
os.stat_result(st_mode=33152, st_ino=244, st_dev=24, st_nlink=1, st_uid=1000, st_gid=100, st_size=262144000000000, st_atime=1693167355, st_mtime=1693167355, st_ctime=1693167355)
答案1
系统ftruncate
调用改变了长度文件的大小,而不是其大小。如果您ls -s
在 ftruncate 之前和之后对文件使用,您将看到实际大小没有改变。
您所做的就是创建一个其中有洞的文件。该空洞是未分配的空间,没有分配给它的块(或在本例中为内存页)。对于处于这种状态的文件或共享内存段,您可以从空洞中读取数据(并获取全零),但在写入之前不会实际分配页面。
当然,如果您尝试写入所有这些页面,系统可能会耗尽内存并崩溃。
答案2
在将某些内容写入该内存之前,不需要任何物理内存。因此,您的操作不必出现在统计数据中。
更准确地说,可能需要一些内存来将所有页面标记为尚未使用,但是 1. 这可能不会显示在统计信息中 2. 如果改为记录最后一页的页数(该页的页数),则可以避免这种情况文件)你曾经使用过的是......好吧,零。
依赖这种行为不是很方便。