不可驱逐缓存的奇怪行为(Linux 内核)

不可驱逐缓存的奇怪行为(Linux 内核)

我在嵌入式 Linux 目标上看到了无法解释的行为(initramfs 和不交换)。

由于没有交换,我预计 /tmp (tmpfs) 中的所有内容都会被标记为不可清除。相反,在使用以下脚本时,我观察到以下情况:

#!/bin/sh
count=1
while true; do
    echo "#$count"
    dd if=/dev/zero of=/tmp/zero$count bs=1M count=10 && cat /proc/meminfo | grep 'Unevictable\|Shmem'
    count=`expr $count + 1`
    sleep 3
done
  • 如果写入许多 10MB 的文件,Shmem 会线性增长,但不可驱逐内存会很快从 0KB 跳到 ~200MB:

    #40
    10+0 records in
    10+0 records out
    10485760 bytes (10.0MB) copied, 0.102484 seconds, 97.6MB/s
    Unevictable:           0 kB
    Shmem:            453776 kB
    #41
    10+0 records in
    10+0 records out
    10485760 bytes (10.0MB) copied, 0.047640 seconds, 209.9MB/s
    Unevictable:           0 kB
    Shmem:            464196 kB
    #42
    10+0 records in
    10+0 records out
    10485760 bytes (10.0MB) copied, 0.101833 seconds, 98.2MB/s
    Unevictable:         884 kB
    Shmem:            474616 kB
    #43
    10+0 records in
    10+0 records out
    10485760 bytes (10.0MB) copied, 0.051686 seconds, 193.5MB/s
    Unevictable:      234612 kB
    Shmem:            485040 kB
    #44
    10+0 records in
    10+0 records out
    10485760 bytes (10.0MB) copied, 0.052157 seconds, 191.7MB/s
    Unevictable:      238568 kB
    Shmem:            495572 kB
    #45
    10+0 records in
    10+0 records out
    10485760 bytes (10.0MB) copied, 0.043332 seconds, 230.8MB/s
    Unevictable:      245332 kB
    Shmem:            505892 kB
    #46
    10+0 records in
    10+0 records out
    10485760 bytes (10.0MB) copied, 0.042653 seconds, 234.4MB/s
    Unevictable:      245332 kB
    Shmem:            516312 kB
    #47
    10+0 records in
    10+0 records out
    10485760 bytes (10.0MB) copied, 0.048478 seconds, 206.3MB/s
    Unevictable:      248384 kB
    Shmem:            526724 kB
    
  • 如果我删除所有零文件,不可回收内存将保持在同一水平。这是否意味着我丢失了所有 RAM?看起来是这样的,因为 OOM 杀手似乎更早被调用。我该如何回收它?

    # rm /tmp/zero*
    # cat /proc/meminfo | grep 'Unevictable\|Shmem'
    Unevictable:      288372 kB
    Shmem:             48412 kB
    
  • 使用 100MB 而非 10MB 的块:

    #1
    100+0 records in
    100+0 records out
    104857600 bytes (100.0MB) copied, 0.422820 seconds, 236.5MB/s
    Unevictable:           0 kB
    Shmem:            150168 kB
    #2
    100+0 records in
    100+0 records out
    104857600 bytes (100.0MB) copied, 0.471385 seconds, 212.1MB/s
    Unevictable:           0 kB
    Shmem:            252516 kB
    #3
    100+0 records in
    100+0 records out
    104857600 bytes (100.0MB) copied, 0.444059 seconds, 225.2MB/s
    Unevictable:           0 kB
    Shmem:            354888 kB
    #4
    100+0 records in
    100+0 records out
    104857600 bytes (100.0MB) copied, 0.414981 seconds, 241.0MB/s
    Unevictable:           0 kB
    Shmem:            457368 kB
    #5
    100+0 records in
    100+0 records out
    104857600 bytes (100.0MB) copied, 5.538392 seconds, 18.1MB/s
    Unevictable:      288264 kB
    Shmem:            559700 kB
    #6
    dd: writing '/tmp/zero6': No space left on device
    

有人可以解释一下观察到的行为吗?在我看来,这看起来像是一个内核错误。

谢谢

答案1

我怀疑它不是 tmpfs – 而是 ramfs。

不可驱逐列表涉及以下类别的不可驱逐页面:

  • 那些由 ramfs 拥有的。

  • 那些映射到SHM_LOCK共享内存区域的。

  • 那些映射到VM_LOCKED[mlock()ed] VMA 中的。

将来,基础设施也许还能处理使页面无法驱逐的其他情况(无论是根据定义还是根据情况)。

https://www.kernel.org/doc/Documentation/vm/unevictable-lru.txt

回答你的问题,红帽将“不可驱逐”总结为“内存量(以千字节为单位),由 pageout 代码发现,因为它被用户程序锁定在内存中,所以不可驱逐。”

阅读完整文档后,似乎出于某种原因,ramfs分配从正常的Inactive(anon)LRU 列表开始。一旦用完可用内存并开始触发回收(页面调出),就会扫描列表,VM 将“发现”锁定的内存并将其移动到不可驱逐列表。

与此相关的是,内核注释这表明“Mlocked”字段可能不会立即解释锁定的页面。(在某些情况下可能会,但我没有检查过)。

NR_MLOCK,       /* mlock()ed pages found and moved off LRU */

我并不是假设内核会一次扫描整个列表,但我希望它会分批扫描。

这个理论的问题在于,如果你没有配置任何交换,我不知道你的内核为什么/如何扫描“匿名”列表。我甚至发现代码-

/* If we have no swap space, do not bother scanning anon pages. */
if (!sc->may_swap || mem_cgroup_get_nr_swap_pages(memcg) <= 0) {
    scan_balance = SCAN_FILE;
    goto out;
}

相关内容