我最近将一些 Java 应用程序转换为使用 Linux 手动配置的大页面运行,如下所述这里。我指出“手动配置”,因为它们不是 透明大页面,这给了我们一些性能问题。
所以现在,我在系统上运行了大约 10 个 tomcat,我想知道每个 tomcat 使用了多少内存。
/proc/meminfo
我可以按照所述获取摘要信息Linux 大页面使用情况统计。
但是我找不到任何可以告诉我每个进程的实际大页面使用情况的工具。
我仔细查看了一下/proc/pid/numa_stat
,发现了一些有趣的信息,这些信息让我看到了这一令人恶心的事情:
function pshugepage () {
HUGEPAGECOUNT=0
for num in `grep 'anon_hugepage.*dirty=' /proc/$@/numa_maps | awk '{print $6}' | sed 's/dirty=//'` ; do
HUGEPAGECOUNT=$((HUGEPAGECOUNT+num))
done
echo process $@ using $HUGEPAGECOUNT huge pages
}
或者用 perl 写成这样:
sub counthugepages {
my $pid=$_[0];
open (NUMAMAPS, "/proc/$pid/numa_maps") || die "can't open numa_maps";
my $HUGEPAGECOUNT=0;
while (my $line=<NUMAMAPS>) {
next unless ($line =~ m{ huge }) ;
next unless ($line =~ m{dirty=});
chomp $line;
$line =~ s{.*dirty=}{};
$line =~ s{\s.*$}{};
$HUGEPAGECOUNT+=$line;
}
close NUMAMAPS;
# we want megabytes out, but we counted 2-megabyte hugepages
return ($HUGEPAGECOUNT*2);
}
它给我的数字是合理的,但我并不确信这种方法是否正确。
环境是四 CPU 戴尔、64GB RAM、RHEL6.3、Oracle JDK 1.7.x(截至 20130728 年的最新版本)
答案1
更新:Red Hat 现在推荐这种方法对于 RHEL5/6 上的进程大页面记帐:
grep -B 11 'KernelPageSize: 2048 kB' /proc/[PID]/smaps \
| grep "^Size:" \
| awk 'BEGIN{sum=0}{sum+=$2}END{print sum/1024}'
我在 procps-ng 开发人员邮件列表中询问了这个问题。他们告诉我:
几个月前,procps-ng/pmap 工具中引入了 hugepage 支持(开关 -XX、-C、-c、-N、-n 应该允许您配置和显示正在运行的内核支持的任何条目)。
我在 Fedora 19 上使用 procps-3.3.8 对此进行了一些实验。我认为它没有给我提供我在问题中所建议的内容中没有得到的任何信息,但至少它具有权威的光环。
FWIW我最终得到以下结果:
.pmaprc 文件包含:
[Fields Display]
Size
Rss
Pss
Referenced
AnonHugePages
KernelPageSize
Mapping
[Mapping]
ShowPath
然后我使用以下命令来提取大页面信息:
pmap -c [process id here] | egrep 'Add|2048'
在 grep 中,“Add”用于标题行。“2048”将抓取内核页面大小为 2048 的任何内容,即大页面。它还将抓取不相关的内容。
以下是一些示例输出:
Address Size Rss Pss Referenced AnonHugePages KernelPageSize Mapping
ed800000 22528 0 0 0 0 2048 /anon_hugepage (deleted)
f7e00000 88064 0 0 0 0 2048 /anon_hugepage (deleted)
fd400000 45056 0 0 0 0 2048 /anon_hugepage (deleted)
7f3753dff000 2052 2048 2048 2048 2048 4 [stack:1674]
7f3759000000 4096 0 0 0 0 2048 /anon_hugepage (deleted)
7f3762d68000 2048 0 0 0 0 4 /usr/lib64/libc-2.17.so
7f376339b000 2048 0 0 0 0 4 /usr/lib64/libpthread-2.17.so
我们只关心 kernelPageSize 为 2048 的行。
我认为它告诉我,我已经在大页面中分配了 159744 KB(22528+88064+45056+4096)的 RAM。我告诉 Java 为其堆使用 128M,并且它有一些其他内存池,因此这是一个合理的数字。Rss & Referenced 0 不太合理,但是测试 Java 程序非常简单,因此它也是合理的。
它与我从上面的 perl 代码片段中获得的数字不一致,因为 perl 只搜索“脏”页面 - 那些实际被使用过的页面。或者是因为 perl 本身就是错误的,我不知道。
我还在一台 RHEL6 机器上尝试了 procps 3.3.9,其中有一些活动的 tomcat 使用了大量大页面内存。Rss 和 Referenced 列全部为 0。这很可能是内核的错误,而不是 procps 的错误,我不知道。
答案2
改进的 perl 脚本
#!/usr/bin/perl
#
sub counthugepages {
my $pid=$_[0];
open (NUMAMAPS, "/proc/$pid/numa_maps") || die "can't open numa_maps";
my $HUGEPAGECOUNT=0;
while (<NUMAMAPS>) {
if (/huge.*dirty=(\d+)/) {
$HUGEPAGECOUNT+=$1;
}
}
close NUMAMAPS;
return ($HUGEPAGECOUNT);
}
printf "%d huge pages\n",counthugepages($ARGV[0]);