??/proc/sys/vm/ 目录是 Linux 系统中的一个特殊目录,它包含了与虚拟内存子系统相关的系统内核参数。这些参数可以用来配置系统的虚拟内存管理策略,包括内存分配、页面置换、内存压缩、NUMA 等方面的设置。用户和系统管理员可以通过修改这些内核参数来调整系统的内存管理行为,以优化系统性能或满足特定的应用需求。
??根据列出的文件名,这些文件涉及到 Linux 操作系统的调优和内核参数的配置。下面逐个分析各个文件的作用和含义:
admin_reserve_kbytes
:该文件用于配置管理员保留的内存大小,以字节为单位。这些内存页不会被分配给普通用户。
compaction_proactiveness
:
compact_memory
:
compact_unevictable_allowed
:
dirty_background_bytes
:
dirty_background_ratio
:
dirty_background_bytes
类似,这个参数定义了后台写回进程开始写回脏页的内存使用比率阈值。dirty_bytes
:
dirty_expire_centisecs
:
dirty_ratio
:
dirtytime_expire_seconds
:这个参数定义了脏页存在时间的上限,在这个时间之后,脏页将被写回到磁盘。
dirty_writeback_centisecs
: 用于配置脏页刷新到磁盘的时间间隔,单位为百分之一秒。
drop_caches
:该参数并非用于配置脏页,而是用于清空文件系统缓存和页缓存,以释放内存。可以通过在这个文件中写入不同的数值来执行不同的清理操作。echo 3 > /proc/sys/vm/drop_caches
, 执行缓存清空操作。数字 3 代表清空页缓存、目录项缓存和 inode 缓存。
13.extfrag_threshold
:这个参数用于控制系统分配连续内存页面的策略。当内存分配请求被满足时,内核会尽量提供连续的物理内存页。“extfrag_threshold” 就是设置内核认为内存碎片过大的阈值。
hugetlb_shm_group
:这个参数是为了支持 HugeTLB(大页面)而设置的。它指定了希望使用大页面的用户空间进程的共享内存分配所需的权限。
laptop_mode
:这个参数是针对笔记本电脑而设计的,用于控制系统在省电模式下的行为。当启用 “laptop_mode” 时,系统会尽量降低功耗,延长电池续航时间。
legacy_va_layout
:这个参数用于启用或禁用内核在用户态地址空间中使用传统的 “VA = PA + PAGE_OFFSET” 布局。通常情况下,不需要手动修改此参数。
lowmem_reserve_ratio
:这个参数决定了系统在低内存条件下要保留多少内存以供内核使用。默认情况下,内核会保留一部分内存,以便能够应对低内存压力和系统任务的需要。
max_map_count
:这个参数限制了每个进程能够创建的内存映射区(vma)的数量。通过限制这个数量,可以提高系统的安全性和稳定性。
memory_failure_early_kill
:这个参数决定了内核对检测到的内存故障的处理方式。当启用 “memory_failure_early_kill” 时,内核会快速杀死出现内存故障的进程以防止进一步的损害。
memory_failure_recovery
:这个参数用于设置内核对内存错误的恢复行为。它决定了内核在检测到内存故障后的下一步操作,如是否尝试修复或替换故障的内存区域。
min_free_kbytes
:是 Linux 内核中的一个调整参数,用于设置最小空闲内存的阈值。它表示内核将尽量保留的空闲内存量,以确保系统具有足够的可用内存来应对突发的内存需求。以页的数量为单位。当内存使用量接近 min_free_kbytes
时,内核会避免分配更多的内存页面,以保留一定的空闲内存。这样做的目的是避免系统因为内存不足而陷入频繁的页面置换操作,以及在处理突发内存需求时能够有一些缓冲空间。
min_slab_ratio
:这个参数用于控制内核中 slab 分配器的空间使用比例。它表示 slab 缓存的最小使用比例,当 slab 缓存的使用比例低于该值时,内核会释放一些 slab 缓存以回收内存空间。
min_unmapped_ratio
:这个参数用于控制内核中未映射内存的使用比例。当未映射内存的使用比例低于该值时,内核会回收未映射的内存页面以释放内存空间。
mmap_min_addr
:这个参数用于限制被非特权进程用于 mmap() 系统调用的地址范围。它指定了 mmap() 返回的映射地址的最小值,防止用户空间进程随意映射低地址空间。
mmap_rnd_bits
和 mmap_rnd_compat_bits
:这两个参数控制 mmap 映射地址的随机化。mmap_rnd_bits 指定了 mmap 映射地址的位数,mmap_rnd_compat_bits 指定了与其他架构上的二进制兼容时的位数。`
nr_hugepages
和 nr_hugepages_mempolicy
:这两个参数用于设置系统中 HugeTLB(大页面)的数量。nr_hugepages 设置为大于 0 的值时,表示分配固定数量的大页面;nr_hugepages_mempolicy 在 NUMA 架构上指定了每个 NUMA 节点分配的大页面数量。
cnr_overcommit_hugepages
:这个参数用于设置系统中额外可动态分配的 HugeTLB(大页面)的数量。当系统的 HugeTLB 使用完时,内核会尝试动态分配额外的 HugeTLB 页面。
numa_stat
文件提供了 NUMA(非统一内存访问)系统的统计信息。。NUMA 是一种多处理器系统架构,其中每个处理器与特定的内存区域(称为 NUMA 节点)关联,而且每个处理器只能直接访问本地节点的内存,对其他节点的访问需要通过交互连接进行。
numa_zonelist_order
:该文件用于指定 NUMA 架构的内存分配策略。
"numa_zonelist_order" 是 Linux 内核中的一个调优参数,用于指定 NUMA(Non-Uniform
Memory Access,非一致性内存访问)系统中内存分配的顺序。在 NUMA 系统中,不同的内存
区域可能与不同的处理器或处理器组相关联,因此需要考虑内存分配的顺序以最大化性能。
该参数的具体数值表示在尝试从本地节点分配内存失败时,内核会尝试从其他 NUMA 节点上
分配内存,并且按照指定的次序依次尝试其他节点。这对于优化应用程序在 NUMA 系统上的
内存访问和性能至关重要。
默认情况下,这个参数的值通常是一个适当的默认值,但可以根据特定的性能需求进行调整。
要注意的是,直接修改这个参数可能会对系统性能产生影响,因此在实际调整时需要谨慎操作
并进行充分的测试和评估。
oom_dump_tasks
:这是一个控制开关,用于启用或禁用当系统内存不足时将 oom_score_adj 值为负的任务信息写入到 /proc
文件系统中的特殊文件 /proc/sys/kernel/panic_on_oom
中。当启用时,内核会将这些进程的信息记录下来,并可用于诊断系统内存用尽的情况。
oom_kill_allocating_task
:此参数控制是否允许内核在 Out-Of-Memory 条件下终止分配内存的进程。当启用时,内核会尝试终止正在分配内存的进程以尝试释放内存。当禁用时,内核会尝试终止具有最高 OOM 分数的进程。
overcommit_kbytes
:这是一个用于控制过度承诺内存的参数,用于指定系统允许的过度承诺的总内存(以 kBytes 为单位)。
overcommit_memory
:该参数用于控制内存过度承诺策略。
OVERCOMMIT_GUESS (0): 这个选项是默认的设置。在这种模式下,内核会根据系统中可用的物理内存
和已分配的虚拟内存的大小来判断是否允许超额分配。例如,当虚拟内存的总量超过物理内存加上交换
空间的大小时,会禁止超额分配。这种模式下的行为通常是比较合理且安全的。
OVERCOMMIT_ALWAYS (1): 这个选项表示内核始终允许超额分配。不论物理内存和已分配的虚拟内存
之间是否有足够的空间,内核都会允许进程进行超额分配。这样做的话,即使系统实际内存不足,也不
会阻止进程进行内存分配操作。但是,当实际可用内存超出物理内存大小时,可能会导致应用程序在使
用超额内存时发生页错误(page fault)。
OVERCOMMIT_NEVER (2): 这个选项表示内核不允许超额分配。当进程请求内存超过操作系统实际可用
的物理内存大小时,内核会阻止超额分配,并抛出 Out-Of-Memory (OOM) 错误,使进程能够适当地
处理内存不足的情况。
overcommit_ratio
:这个参数用于指定内存过度承诺的比率。它表示了系统内存大小与所允许的过度承诺内存大小之间的比率。
page-cluster
:这个参数用于设置内存页合并的阈值。内核会尝试合并空闲内存页,以减少内存碎片和提高内存使用效率。
page_lock_unfairness
:这个参数用于控制内存页锁定时的公平性策略。当启用时,内核会尽量公平地处理内存页的锁定请求。
panic_on_oom
:此参数是一个开关,用于控制当系统内存不足时是否触发 kernel panic。当启用时,系统将在内存耗尽时触发 panic;当禁用时,系统会尝试通过终止进程或其他手段来尝试恢复。
percpu_pagelist_high_fraction
: 决定了用于单个 CPU 的 per-CPU 内存页面列表的最大比例。per-CPU 页面列表是系统用于分配给每个 CPU 的内存页面的特殊列表。
stat_interval
: 用于设置内存统计信息输出到 /proc/zoneinfo 文件的时间间隔。
stat_refresh
: 控制在刷新内存统计信息时是否清零统计数据。设置为 1 时表示清零,设置为 0 时表示不清零。
swappiness
: 系统用来管理内存和交换空间的参数。它定义了系统在何时、以及何种程度上使用交换空间来替换内存。
unprivileged_userfaultfd
: 决定是否允许非特权用户创建和使用 userfaultfd 文件描述符(用于处理用户态页缺失异常)。
user_reserve_kbytes
: 为非特权进程保留的物理内存页大小,确保非特权用户总是能分配到一定数量的内存页。
vfs_cache_pressure
: 用于控制内核释放缓存页的速度。较高的值会导致更积极地释放缓存,以腾出更多的内存。
watermark_boost_factor
: 这个参数用于设定内核在内存压力情况下提高回收行为的程度。当系统内存低于 “水位线”(watermark)时,内核将执行更积极的内存回收。watermark_boost_factor
的值表示水位线以下可用内存大小的增加倍率。默认值是 150,表示内核会尝试回收额外的 50%(1.5 倍)超过水位线以下的可用内存。
watermark_scale_factor
: 这个参数用于设置内核在内存压力情况下,何时开始进行内存回收。watermark_scale_factor
的值表示系统内存大小的一部分,作为水位线以下的可用内存大小。默认值是 10,表示内核开始回收内存的临界点是当前系统可用内存的 10%。
??要修改这些参数的值,可以通过 sysctl
命令或直接修改 /proc/sys/vm/watermark_boost_factor
和 /proc/sys/vm/watermark_scale_factor
文件。
zone_reclaim_mode
: 控制内核中区域再分配的行为。这个参数决定了内核在 NUMA 系统中如何管理内存的分配和回收。??这些文件中的每一个都是与调优和配置内核参数相关的,可以通过修改这些文件来改变系统的行为和性能。注意,在改动这些文件之前,需要了解对应的参数的含义和影响,并谨慎调整系统设置。
??与/proc/sys/vm/目录中的文件具有相同功能的Linux API函数和C库函数包括:
sysctl
函数:可以通过sysctl函数读取和修改内核参数。可以使用sysctl函数直接读取和修改/proc/sys/vm/目录下的文件。
fopen
、fread
、fwrite
函数:可以使用C标准库函数来打开、读取和写入/proc/sys/vm/目录下的文件。
open
、read
、write
函数:可以使用Linux系统调用函数来打开、读取和写入/proc/sys/vm/目录下的文件。
sscanf
函数:可以使用sscanf函数将文件中的内容解析为变量,方便进行处理。
fprintf
函数:可以使用fprintf函数将变量的值格式化后写入文件中。
??这些函数和方法可以帮助读取和修改/proc/sys/vm/目录下的文件的内容,实现对相应内核参数的操作。下面是使用C语言和相关函数来读取和修改/proc/sys/vm/目录下文件的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sysctl.h>
int main() {
int mib[2];
size_t len;
int swappiness;
// 将参数名称转换为 MIB 值
mib[0] = CTL_VM;
mib[1] = VM_SWAPPINESS;
len = sizeof(swappiness);
// 获取swappiness值
if (sysctl(mib, 2, &swappiness, &len, NULL, 0) < 0) {
perror("sysctl");
exit(1);
}
printf("Swappiness: %d\n", swappiness);
return 0;
}
如果在使用 `sysctl` 函数时出现 "Function not implemented" 的错误,这意味着该函数或特定
的系统参数不受当前操作系统或内核的支持。
这种情况可能发生在以下几种情况下:
1. 操作系统版本较旧:某些系统参数可能是在后续的操作系统版本中引入的,因此在较旧的版本中
可能不受支持。尝试升级操作系统或使用较新版本的内核可能会解决这个问题。
2. 系统参数未启用:某些系统可能禁用了特定的系统参数,以增加安全性或限制某些操作。在这种
情况下,你将无法使用 `sysctl` 函数来访问或修改这些参数。
3. 编译选项不正确:有些发行版或内核配置可能不包括对 `sysctl` 函数的支持。在这种情况下,
你将无法使用该函数,除非重新编译内核或启用相关的编译选项。
#include <stdio.h>
int main() {
FILE* file;
int value;
// 读取内核参数
file = fopen("/proc/sys/vm/swappiness", "r");
if (file == NULL) {
perror("Failed to open file");
return 1;
}
fscanf(file, "%d", &value);
printf("vm.swappiness: %d\n", value);
fclose(file);
// 修改内核参数
file = fopen("/proc/sys/vm/swappiness", "w");
if (file == NULL) {
perror("Failed to open file");
return 1;
}
fprintf(file, "%d", 10);
fclose(file);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd;
char buffer[1024];
ssize_t bytes_read;
// 读取内核参数
fd = open("/proc/sys/vm/swappiness", O_RDONLY);
if (fd == -1) {
perror("Failed to open file");
return 1;
}
bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read == -1) {
perror("Failed to read file");
return 1;
}
buffer[bytes_read] = '\0';
printf("vm.swappiness: %s\n", buffer);
close(fd);
// 修改内核参数
fd = open("/proc/sys/vm/swappiness", O_WRONLY);
if (fd == -1) {
perror("Failed to open file");
return 1;
}
char new_value[] = "10";
ssize_t bytes_written = write(fd, new_value, sizeof(new_value) - 1);
if (bytes_written == -1) {
perror("Failed to write file");
return 1;
}
close(fd);
return 0;
}
??以上示例代码展示了不同函数和方法读取和修改/proc/sys/vm/目录下文件的方式。具体的操作根据不同的需求和情况可以选择适用的方法。