私は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を更新した後、プロセスの実行中に指定された数のマップを取得できるようになったことに注意してください。