【问题标题】:Measuring memory usage of a process on Linux在 Linux 上测量进程的内存使用情况
【发布时间】:2010-12-25 18:58:09
【问题描述】:
我正在尝试测量 linux 上一个进程(java 程序)的内存使用情况,并有两个与此相关的问题:
我尝试使用脚本ps_mem.py(对 /proc/$PID/smaps 中的值求和),总内存使用量的峰值约为 135MB(私有和共享内存)。共享内存量小于 1MB。尝试将 Valgrind 与 massif 工具 valgrind --tool=massif --trace-children=yes --stacks=yes java myProgram 一起使用会在内存使用高峰时产生大约 10MB。
现在据我了解,堆是我程序的变量存储的地方,这是否意味着两种方法之间的区别在于代码本身(包括jvm)占用的空间?
如果同一程序具有不同数量的 RAM 或/和使用不同的处理器(ARM 或 x86),是否相同程序在不同机器上使用不同数量的内存?
【问题讨论】:
标签:
java
linux
memory-management
valgrind
【解决方案1】:
- 视情况而定。
-
smaps 中的许多共享内存映射直接由磁盘上的库/二进制文件支持。虽然这些页面的占用确实很重要,但它并不那么重要,因为系统可以随时删除这些页面,并在需要时从磁盘重新加载它们。
- 任何脏的或私有的东西都只属于当前进程(好吧,如果你的程序分叉而没有执行程序,则进程树)。这一点更重要,因为如果系统需要将这些页面推出内存,则必须将它们保存以进行交换。
- 地块测量的内容可能与后者相关。但是,JVM 本身(没有您的程序)占用的内存在两者中。
- 是的。 Java 或其使用的库可能会根据可用 RAM 的大小调整其内存模型。在不同的架构上,您使用完全不同的二进制文件,这些二进制文件可能更大或更小,或者排列方式不同,或者使用不同的 JIT 和内存管理策略。
【解决方案2】:
除此之外还有一个类似的问题,在这里回答同样的问题,让人们知道当前 linux proc stat vm info 是如何不准确的。
Valgrind 可以显示详细信息,但它会显着降低目标应用程序的速度,并且大多数情况下它会改变应用程序的行为。
我假设每个人都想知道 WRT“内存使用情况”如下...
在linux中,单个进程可能使用的物理内存量大致可以分为以下几类。
- M.a 匿名映射内存
- .p 私有
- .d 脏 == malloc/mmapped 堆和堆栈分配和写入内存
- .c clean == malloc/mmapped 堆和堆栈内存一旦分配、写入、然后释放,但尚未回收
- .s 共享
- .d 脏 == 应该没有
- .c clean == 应该没有
- M.n 命名映射内存
- .p 私有
- .d 脏 == 文件映射写入内存私有
- .c clean == 映射程序/库文本私有映射
- .s 共享
- .d 脏 == 文件映射写入内存共享
- .c clean == 映射库文本共享映射
我更愿意按以下方式获取数字,以便以最少的开销获得实数。
您必须将这些总结起来才能将 ps 显示为 RSS 的内容进行划分,并获得更准确的数字以免混淆。
/proc/(pid)/status 试图显示这些数字,但它们失败了。
因此,与其尝试将 [anon]、[stack] 正确标记到每个映射,我的愿望是
那个 linux 内核的人将主线 proc 入口代码汇总并显示这些 M.a.p.d、M.a.p.c、M.n.p.d、....数字。
嵌入式 linux 的人会很高兴恕我直言。
M.a.p.d:
awk '/^[0-9a-f]/{if ($6=="") {anon=1}else{anon=0}} /Private_Dirty/{if(anon) {asum+=$2}else{nasum+=$2}} END{printf "sum=%d\n",asum}' /proc/<pid>/smaps
M.a.p.c:
awk '/^[0-9a-f]/{if ($6=="") {anon=1}else{anon=0}} /Private_Clean/{if(anon) {asum+=$2}else{nasum+=$2}} END{printf "sum=%d\n",asum}' /proc/<pid>/smaps
M.n.p.d:...等等
【解决方案3】:
对于#1,共享内存是(可能)被多个进程使用的内存。这基本上是如果您在多个进程中运行相同的二进制文件或不同的进程正在使用共享库。堆是存储分配内存的地方(当您在 Java 中使用 new 时)。由于 Java 有自己的虚拟机,它会在进程级别分配大量内存,而这在 Java 代码中是看不到的。我认为是的,这 135 MB 的大部分来自 JVM 代码/数据本身。但是,堆栈也会占用内存(当您进行函数调用并具有局部变量时)。
对于#2,当我们让内存等于 RAM + 交换空间时,不同数量的 RAM 不会影响使用多少“内存”。但是,不同的处理器(尤其是当我们谈论 32 位和 64 位时)可能使用不同数量的内存。此外,编译进程的方式可能会改变使用的内存量,因为您可以指示编译器优化内存占用而不是速度,以及完全禁用部分或全部优化。
【解决方案4】:
您可能想看看 JConsole。根据您的测量目的,事情可能会很棘手。如果您想知道 Java 程序的内存使用情况,那么测量进程内存使用情况的工具将不准确,因为它们会显示 JVM 以及您的程序使用的内存。
至于massif工具你应该知道JVM的一部分会存储在堆栈上,而java代码本身可能会在堆上(因为它是JVM的变量),我不太了解JVM 说的。