linux – 更改sysctl是否需要重启进程?

我在redhat机器上.我正在通过sysctl更改max_map_count的值:

# sysctl vm.max_map_count
vm.max_map_count = 65530
# sysctl -w vm.max_map_count=655300
vm.max_map_count = 655300
# sysctl vm.max_map_count
vm.max_map_count = 655300

然后我将该值写入/etc/sysctl.conf,以便继续重启.

我这样做是为了满足特定长期服务的munmap需求.我知道修改sysctl值对系统来说是立竿见影的.我的问题是:我是否需要重新启动单个服务才能使此更新设置对该特定运行进程生效,或者更新后的计数限制是否立即应用于正在运行的进程?

解决方法:

运行以下程序,我发现该过程不需要重新启动.也就是说,设置max_map_count会立即对所有进程生效.

(我从https://github.com/linux-test-project/ltp/blob/master/testcases/kernel/mem/tunable/max_map_count.c#L171中获取了一部分代码来编写以下内容.请注意,该许可证是GPLv2或更高版本.)

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>


const char* MAX_MAP_PROC_FILE = "/proc/sys/vm/max_map_count";

/* This is a filter to exclude map entries which aren't accounted
 * for in the vm_area_struct's map_count.
 */
static bool filter_map(const char *line)
{
    char buf[BUFSIZ];
    int ret;

    ret = sscanf(line, "%*p-%*p %*4s %*p %*2d:%*2d %*d %s", buf);
    if (ret != 1)
        return false;

#if defined(__x86_64__) || defined(__x86__)
    /* On x86, there's an old compat vsyscall page */
    if (!strcmp(buf, "[vsyscall]"))
        return true;
#elif defined(__ia64__)
    /* On ia64, the vdso is not a proper mapping */
    if (!strcmp(buf, "[vdso]"))
        return true;
#elif defined(__arm__)
    /* Skip it when run it in aarch64 */
    if ((!strcmp(un.machine, "aarch64"))
    || (!strcmp(un.machine, "aarch64_be")))
        return false;

    /* Older arm kernels didn't label their vdso maps */
    if (!strncmp(line, "ffff0000-ffff1000", 17))
        return true;
#endif

    return false;
}


static long count_maps(pid_t pid)
{
    FILE *fp;
    size_t len;
    char *line = NULL;
    char maps_proc_name[BUFSIZ];
    long map_count = 0;

    snprintf(maps_proc_name, BUFSIZ, "/proc/%d/maps", pid);
    fp = fopen(maps_proc_name, "r");
    if (fp == NULL) {
    fprintf(stderr, "Could not open proc file: %s\n", maps_proc_name);
    exit(1);
    }
    while (getline(&line, &len, fp) != -1) {
        /* exclude vdso and vsyscall */
        if (filter_map(line))
            continue;
        map_count++;
    }
    fclose(fp);

    return map_count;
}


static void update_max_map()
{
    FILE *fp = fopen(MAX_MAP_PROC_FILE, "w");
    if (fp == NULL) {
        fprintf(stderr, "Could not open proc file: %s\n", MAX_MAP_PROC_FILE);
        exit(1);
    }

    fprintf(fp, "%d", 655300);

    fclose(fp);
}

static void map_and_print_count()
{
    int num_lines = 0;
    while (mmap(NULL, 1, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0) != MAP_FAILED)
    {
    }
    printf("mmap failed with errno: %s\n", strerror(errno));

    num_lines = count_maps(getpid());
    printf("number of lines: %d\n", num_lines);
}

int
main(int argc, char* argv[])
{
    int num_lines = 0;
    num_lines = count_maps(getpid());

    printf("number of lines to start: %d\n", num_lines);
    map_and_print_count();

    update_max_map();
    map_and_print_count();

    return 0;
}

运行此命令会提供以下输出:

# gcc -Wall -o max_map_count max_map_count.c  && ./max_map_count
number of lines to start: 16
mmap failed with errno: Cannot allocate memory
number of lines: 65531
mmap failed with errno: Cannot allocate memory
number of lines: 655301

请注意,更新max_map_count后,该过程现在能够在进程运行时获取指定数量的映射.

上一篇:redis-server的三个警告


下一篇:linux – sysctl -a从哪里打印所有内核参数?