Java 使用cgexec vs cgroup.procs进行使用cgroup的内存记帐
昨天我遇到了一个有趣的情况,使用cgroups内存控制器。我一直认为cgroups报告的内存是进程的总内存消耗量,但事实似乎并非如此 我编写了以下用于测试的Java编程:Java 使用cgexec vs cgroup.procs进行使用cgroup的内存记帐,java,linux,linux-kernel,cgroups,Java,Linux,Linux Kernel,Cgroups,昨天我遇到了一个有趣的情况,使用cgroups内存控制器。我一直认为cgroups报告的内存是进程的总内存消耗量,但事实似乎并非如此 我编写了以下用于测试的Java编程: import java.util.Scanner; class TestApp { public static void main(String args[]) { int[] arr; Scanner in = new Scanner(System.in); System.out.prin
import java.util.Scanner;
class TestApp {
public static void main(String args[]) {
int[] arr;
Scanner in = new Scanner(System.in);
System.out.println("Press enter to allocate memory");
in.nextLine();
arr = new int[1024*1024];
System.out.println("Allocated memory");
while(true);
}
}
使用cgexec
运行上述操作时,内存使用情况与echo
将JVM的PID插入cgroup的cgroup.procs
文件时大不相同。似乎在进程被放入cgroup之后,cgroup会报告进程的内存使用情况
cgroup如何解释内存?似乎在使用cgexec
时,JVM的消耗量会被考虑在内。另一方面,当在cgroup外部启动JVM,然后通过将PID写入cgroup.procs
文件将其移动到其中时,memory.usage(以字节为单位)中报告的内存消耗量保持为零,直到我按enter键,消耗量按预期增加到1024*1024*4
此外,例如,cgroups
报告的内存消耗与top
报告的内存消耗并不完全相同
编辑:创建以下C程序并将其用于测试。我也看到了同样的结果。如果使用cgclassify
,则内存利用率保持为0,直到按enter键。另一方面,当使用cgexec
时,在按下enter键之前,内存利用率大于0
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Press ENTER to consume memory\n");
getchar();
char *ptr = malloc(1024*1024);
if (ptr == NULL) {
printf("Out of memory");
exit(1);
}
memset(ptr, 0, 1024*1024);
printf("Press ENTER to quit\n");
getchar();
return(0);
}
#包括
#包括
int main(){
printf(“按ENTER键消耗内存\n”);
getchar();
char*ptr=malloc(1024*1024);
如果(ptr==NULL){
printf(“内存不足”);
出口(1);
}
memset(ptr,0,1024*1024);
printf(“按ENTER键退出\n”);
getchar();
返回(0);
}
当您分配一个页面并由一个进程进行分页时,分配的内存会被标记一个标识符,告诉内核该内存属于哪个特定的内存控制器cgroup(显然,该内存也将属于cgroup的任何父级)
将进程迁移到新cgroup时,已分配的内存不会更改其标记。“重新标记”所有内容将非常昂贵,甚至没有意义(假设一个页面由两个进程共享,而您只将其中一个迁移到另一个cgroup。“新”标记需要是什么?它现在由不同cgroup中的两个进程使用…)
因此,如果您位于/sys/fs/cgroup/memory cgroup中(即您的任务组ID在/sys/fs/cgroup/memory/tasks中提到,而不是在该cgroup的任何子级的任务文件中提到),那么您分配的任何内容都只针对该cgroup和该cgroup进行计算
当迁移到其他cgroup(或子cgroup)时,只有新的内存分配被标记为属于该新cgroup
cgexec将在cgroup中启动JVM,因此在初始化时分配的任何内容都将属于为您执行的内容而创建的cgroup
如果在内存控制器的根cgroup中启动一个JVM,那么初始化JVM时分配和触摸的任何东西都将属于根cgroup
一旦您将JVM迁移到它自己的私有cgroup(使用任何一种机制),然后分配和触摸一些页面,显然这些页面将属于新的cgroup。尝试用C或C++@BasileStrynkevich编写相同的代码谢谢您的建议。我终于能够四处走动并编写一个示例C程序。我看到了同样的结果。。。有什么想法吗?换句话说,如果您希望根据特定于应用程序的内存控制器cgroup计算所有内存,那么您应该创建cgroup并在开始应用程序之前将“您自己”移动到该cgroup。--要手动执行此操作,只需在根cgroup下创建一个目录,然后在shell中创建,例如echo$$>/sys/fs/cgroup/memory/my_private\u cgroup/tasks。如果您从该shell(现在位于my_private_cgroup cgroup中)启动JVM,它从一开始就位于正确的cgroup中。谢谢Alexis。这上面有文件吗?我在memory.txt中找不到任何内容