一种确定进程“真实”内存使用的方法,即私有的脏RSS?

时间:2020-12-23 02:39:53

Tools like 'ps' and 'top' report various kinds of memory usages, such as the VM size and the Resident Set Size. However, none of those are the "real" memory usage:

像“ps”和“top”这样的工具会报告各种各样的内存使用情况,比如VM大小和驻留的设置大小。然而,这些都不是真正的内存使用:

  • Program code is shared between multiple instances of the same program.
  • 程序代码在同一个程序的多个实例之间共享。
  • Shared library program code is shared between all processes that use that library.
  • 共享库程序代码在使用该库的所有进程之间共享。
  • Some apps fork off processes and share memory with them (e.g. via shared memory segments).
  • 有些应用程序可以通过共享内存段(例如共享内存段)来派生进程并共享内存。
  • The virtual memory system makes the VM size report pretty much useless.
  • 虚拟内存系统使得VM的大小报告几乎毫无用处。
  • RSS is 0 when a process is swapped out, making it not very useful.
  • 当一个进程被交换出去时,RSS是0,这使得它不是很有用。
  • Etc etc.
  • 等等。

I've found that the private dirty RSS, as reported by Linux, is the closest thing to the "real" memory usage. This can be obtained by summing all Private_Dirty values in /proc/somepid/smaps.

我发现,正如Linux所报道的,私有的脏RSS是最接近“真实”内存使用的东西。这可以通过对/proc/somepid/smaps中的所有Private_Dirty值求和得到。

However, do other operating systems provide similar functionality? If not, what are the alternatives? In particular, I'm interested in FreeBSD and OS X.

但是,其他操作系统也提供类似的功能吗?如果没有,还有其他选择吗?特别是,我对FreeBSD和OS X感兴趣。

9 个解决方案

#1


35  

On OSX the Activity Monitor gives you actually a very good guess.

在OSX上,活动监视器会给你一个很好的猜测。

Private memory is for sure memory that is only used by your application. E.g. stack memory and all memory dynamically reserved using malloc() and comparable functions/methods (alloc method for Objective-C) is private memory. If you fork, private memory will be shared with you child, but marked copy-on-write. That means as long as a page is not modified by either process (parent or child) it is shared between them. As soon as either process modifies any page, this page is copied before it is modified. Even while this memory is shared with fork children (and it can only be shared with fork children), it is still shown as "private" memory, because in the worst case, every page of it will get modified (sooner or later) and then it is again private to each process again.

私有内存是用于确定只用于应用程序的内存。使用malloc()和类似的函数/方法(Objective-C的alloc方法)动态保留栈内存和所有内存,是私有内存。如果您使用fork,私有内存将与您共享,但是标记为copy-on-write。这意味着只要页面没有被进程(父进程或子进程)修改,就会在它们之间共享。只要进程修改了任何页面,这个页面就会在修改之前被复制。尽管这个内存是与fork子共享的(它只能与fork子共享),但它仍然被显示为“私有”内存,因为在最坏的情况下,它的每一页都将被修改(迟早),然后它又会被再次私有到每个进程。

Shared memory is either memory that is currently shared (the same pages are visible in the virtual process space of different processes) or that is likely to become shared in the future (e.g. read-only memory, since there is no reason for not sharing read-only memory). At least that's how I read the source code of some command line tools from Apple. So if you share memory between processes using mmap (or a comparable call that maps the same memory into multiple processes), this would be shared memory. However the executable code itself is also shared memory, since if another instance of your application is started there is no reason why it may not share the code already loaded in memory (executable code pages are read-only by default, unless you are running your app in a debugger). Thus shared memory is really memory used by your application, just like private one, but it might additionally be shared with another process (or it might not, but why would it not count towards your application if it was shared?)

共享内存是当前共享的内存(在不同进程的虚拟进程空间中可以看到相同的页面),或者可能在将来共享(例如只读内存,因为没有理由不共享只读内存)。至少这是我从苹果读取一些命令行工具源代码的方法。因此,如果在使用mmap(或将相同的内存映射到多个进程)的进程之间共享内存,这将是共享内存。然而,可执行代码本身也是共享内存,因为如果您的应用程序的另一个实例已经启动,那么它就没有理由不共享内存中已经加载的代码(默认情况下,可执行代码页是只读的,除非您在调试器中运行您的应用程序)。因此,共享内存实际上是您的应用程序使用的内存,就像私有内存一样,但是它可能还会与另一个进程共享(或者可能不会,但是如果它被共享了,为什么它不计算在您的应用程序中呢?)

Real memory is the amount of RAM currently "assigned" to your process, no matter if private or shared. This can be exactly the sum of private and shared, but usually it is not. Your process might have more memory assigned to it than it currently needs (this speeds up requests for more memory in the future), but that is no loss to the system. If another process needs memory and no free memory is available, before the system starts swapping, it will take that extra memory away from your process and assign it another process (which is a fast and painless operation); therefor your next malloc call might be somewhat slower. Real memory can also be smaller than private and physical memory; this is because if your process requests memory from the system, it will only receive "virtual memory". This virtual memory is not linked to any real memory pages as long as you don't use it (so malloc 10 MB of memory, use only one byte of it, your process will get only a single page, 4096 byte, of memory assigned - the rest is only assigned if you actually ever need it). Further memory that is swapped may not count towards real memory either (not sure about this), but it will count towards shared and private memory.

真正的内存是当前“分配”到您的进程中的RAM的数量,无论是私有的还是共享的。这可以是私有和共享的总和,但通常不是。您的进程可能会有更多的内存分配给它,而不是当前的需求(这会加快请求,以便将来有更多的内存),但是这对系统来说是没有损失的。如果另一个进程需要内存,并且没有空闲内存可用,在系统开始交换之前,它将从您的进程中移除额外的内存并分配另一个进程(这是一个快速且无痛的操作);因此,您的下一个malloc调用可能会稍微慢一些。实际内存也可以小于私有内存和物理内存;这是因为如果您的进程请求系统内存,它将只接收“虚拟内存”。这个虚拟内存不与任何真正的内存页面,只要你不使用它(所以malloc 10 MB的内存,只使用一个字节,您的流程将会只有一个页面,4096字节的内存分配,其余的只是如果你真的需要它)。交换的内存可能不计入实际内存(不确定这一点),但它将计算共享内存和私有内存。

Virtual memory is the sum of all address blocks that are consider valid in your apps process space. These addresses might be linked to physical memory (that is again private or shared), or they might not, but in that case they will be linked to physical memory as soon as you use the address. Accessing memory addresses outside of the known addresses will cause a SIGBUS and your app will crash. When memory is swapped, the virtual address space for this memory remains valid and accessing those addresses causes memory to be swapped back in.

虚拟内存是在你的应用程序空间中被认为有效的所有地址块的总和。这些地址可能与物理内存(再次是私有的或共享的)相关联,或者它们可能不链接,但是在这种情况下,当您使用地址时,它们将与物理内存联系起来。访问已知地址之外的内存地址将导致SIGBUS,而您的应用程序将崩溃。当内存被交换时,此内存的虚拟地址空间仍然有效,并且访问这些地址将导致内存被交换回。

Conclusion:
If your app does not explicitly or implicitly use shared memory, private memory is the amount of memory your app needs because of the stack size (or sizes if multithreaded) and because of the malloc() calls you made for dynamic memory. You don't have to care a lot for shared or real memory in that case.

结论:如果您的应用程序没有显式地或隐式地使用共享内存,那么私有内存就是您的应用程序需要的内存数量,因为栈大小(或者是多线程的大小),以及由于malloc()调用您为动态内存所做的调用。在这种情况下,您不必关心共享或实际内存。

If your app uses shared memory, and this includes a graphical UI, where memory is shared between your application and the WindowServer for example, then you might have a look at shared memory as well. A very high shared memory number may mean you have too many graphical resources loaded in memory at the moment.

如果你的应用程序使用共享内存,这包括一个图形用户界面,在你的应用程序和windows服务器之间共享内存,那么你也可以查看共享内存。一个非常高的共享内存号可能意味着您在内存中有太多的图形资源。

Real memory is of little interest for app development. If it is bigger than the sum of shared and private, then this means nothing other than that the system is lazy at taken memory away from your process. If it is smaller, then your process has requested more memory than it actually needed, which is not bad either, since as long as you don't use all of the requested memory, you are not "stealing" memory from the system. If it is much smaller than the sum of shared and private, you may only consider to request less memory where possible, as you are a bit over-requesting memory (again, this is not bad, but it tells me that your code is not optimized for minimal memory usage and if it is cross platform, other platforms may not have such a sophisticated memory handling, so you may prefer to alloc many small blocks instead of a few big ones for example, or free memory a lot sooner, and so on).

实际内存对应用程序开发没有多大兴趣。如果它大于共享和私有的总和,那么这就意味着系统很懒,将内存从进程中删除。如果它更小,那么您的进程请求的内存比实际需要的要多,这也不坏,因为只要您不使用所有被请求的内存,就不会从系统中“窃取”内存。如果它是远小于共享和私有的总和,你可能只考虑请求更少内存在可能的情况下,当你有点over-requesting内存(这并不坏,但是它告诉我,你的代码并不是最小的优化内存使用,如果它是跨平台的,其他平台可能没有这样一个复杂的内存处理,所以你可能喜欢alloc许多小块而不是几大的例如,或空闲内存很多早,等等)。

If you are still not happy with all that information, you can get even more information. Open a terminal and run:

如果你仍然对这些信息不满意,你可以得到更多的信息。打开终端并运行:

sudo vmmap <pid>

where is the process ID of your process. This will show you statistics for EVERY block of memory in your process space with start and end address. It will also tell you where this memory came from (A mapped file? Stack memory? Malloc'ed memory? A __DATA or __TEXT section of your executable?), how big it is in KB, the access rights and whether it is private, shared or copy-on-write. If it is mapped from a file, it will even give you the path to the file.

您的进程的进程ID在哪里。这将向您显示进程空间中带有起始地址和结束地址的每个内存块的统计信息。它还会告诉您这个内存来自哪里(一个映射文件?栈内存?分配的内存?您的可执行文件的__DATA或__TEXT部分?),它在KB中有多大,访问权限以及它是私有的、共享的还是复制的。如果它从一个文件映射,它甚至会给你文件的路径。

If you want only "actual" RAM usage, use

如果您只需要“实际”RAM的使用,请使用。

sudo vmmap -resident <pid>

Now it will show for every memory block how big the memory block is virtually and how much of it is really currently present in physical memory.

现在它将显示每个内存块的大小,内存块的大小,以及它当前在物理内存中有多少。

At the end of each dump is also an overview table with the sums of different memory types. This table looks like this for Firefox right now on my system:

在每个转储的末尾也是一个带有不同内存类型和的概述表。这个表格现在在我的系统上是这样的:

REGION TYPE             [ VIRTUAL/RESIDENT]
===========             [ =======/========]
ATS (font support)      [   33.8M/   2496K]
CG backing stores       [   5588K/   5460K]
CG image                [     20K/     20K]
CG raster data          [    576K/    576K]
CG shared images        [   2572K/   2404K]
Carbon                  [   1516K/   1516K]
CoreGraphics            [      8K/      8K]
IOKit                   [  256.0M/      0K]
MALLOC                  [  256.9M/  247.2M]
Memory tag=240          [      4K/      4K]
Memory tag=242          [     12K/     12K]
Memory tag=243          [      8K/      8K]
Memory tag=249          [    156K/     76K]
STACK GUARD             [  101.2M/   9908K]
Stack                   [   14.0M/    248K]
VM_ALLOCATE             [   25.9M/   25.6M]
__DATA                  [   6752K/   3808K]
__DATA/__OBJC           [     28K/     28K]
__IMAGE                 [   1240K/    112K]
__IMPORT                [    104K/    104K]
__LINKEDIT              [   30.7M/   3184K]
__OBJC                  [   1388K/   1336K]
__OBJC/__DATA           [     72K/     72K]
__PAGEZERO              [      4K/      0K]
__TEXT                  [  108.6M/   63.5M]
__UNICODE               [    536K/    512K]
mapped file             [  118.8M/   50.8M]
shared memory           [    300K/    276K]
shared pmap             [   6396K/   3120K]

What does this tell us? E.g. the Firefox binary and all library it loads have 108 MB data together in their __TEXT sections, but currently only 63 MB of those are currently resident in memory. The font support (ATS) needs 33 MB, but only about 2.5 MB are really in memory. It uses a bit over 5 MB CG backing stores, CG = Core Graphics, those are most likely window contents, buttons, images and other data that is cached for fast drawing. It has requested 256 MB via malloc calls and currently 247 MB are really in mapped to memory pages. It has 14 MB space reserved for stacks, but only 248 KB stack space is really in use right now.

这告诉我们什么?例如,Firefox二进制文件和所有它装载的所有库在它们的__TEXT部分中都有108 MB的数据,但是目前只有63 MB的数据是驻留在内存中的。字体支持(ATS)需要33 MB,但只有大约2.5 MB内存。它使用了超过5mb的CG支持存储,CG =核心图形,这些是最可能的窗口内容,按钮,图像和其他缓存的快速绘图数据。它通过malloc调用请求256 MB,而当前的247 MB确实映射到内存页面。它预留了14 MB空间用于堆栈,但是现在只有248 KB的堆栈空间正在使用。

vmmap also has a good summary above the table

vmmap在表上也有一个很好的总结。

ReadOnly portion of Libraries: Total=139.3M resident=66.6M(48%) swapped_out_or_unallocated=72.7M(52%)
Writable regions: Total=595.4M written=201.8M(34%) resident=283.1M(48%) swapped_out=0K(0%) unallocated=312.3M(52%)

And this shows an interesting aspect of the OS X: For read only memory it plays no role if it is swapped out or simply unallocated; there is only resident and not resident. For writable memory this makes a difference (in my case 52% of all requested memory has never been used and is such unallocated, 0% of memory has been swapped out to disk)

这显示了OS X的一个有趣的方面:对于只读内存,如果它被换出或只是没有分配,它就不会起作用;只有居民而非居民。对于可写的内存,这是有区别的(在我的情况下,所有请求的内存中有52%从未被使用过,并且是这样未分配的,内存的0%已被交换到磁盘)

#2


8  

On Linux, you may want the PSS (proportional set size) numbers in /proc/self/smaps. A mapping's PSS is its RSS divided by the number of processes which are using that mapping.

在Linux上,您可能想要PSS(比例集大小)在/proc/self/smaps中的数字。映射的PSS是它的RSS,除以使用该映射的进程的数量。

#3


4  

Top knows how to do this. It shows VIRT, RES and SHR by default on Debian Linux. VIRT = SWAP + RES. RES = CODE + DATA. SHR is the memory that may be shared with another process (shared library or other memory.)

Top知道怎么做。它在Debian Linux上默认显示VIRT、RES和SHR。交换+ RES =代码+数据。SHR是可以与另一个进程共享的内存(共享库或其他内存)。

Also, 'dirty' memory is merely RES memory that has been used, and/or has not been swapped.

另外,“脏”内存仅仅是被使用过的内存,并且/或没有被交换。

It can be hard to tell, but the best way to understand is to look at a system that isn't swapping. Then, RES - SHR is the process exclusive memory. However, that's not a good way of looking at it, because you don't know that the memory in SHR is being used by another process. It may represent unwritten shared object pages that are only used by the process.

很难说,但最好的理解方式是看一个不交换的系统。然后,RES - SHR是进程独占内存。但是,这并不是一个好的方法,因为您不知道SHR中的内存正在被另一个进程使用。它可能表示仅由进程使用的未写的共享对象页。

#4


4  

You really can't.

你真的不能。

I mean, shared memory between processes... are you going to count it, or not. If you don't count it, you are wrong; the sum of all processes' memory usage is not going to be the total memory usage. If you count it, you are going to count it twice- the sum's not going to be correct.

我是说,进程之间共享内存…你要数一下吗?如果你不去数它,那你就错了;所有进程内存使用的总和不会是总内存使用量。如果你数一数,你就会数一遍,总数不会是正确的。

Me, I'm happy with RSS. And knowing you can't really rely on it completely...

我对RSS很满意。知道你不能完全依赖它……

#5


4  

You can get private dirty and private clean RSS from /proc/pid/smaps

您可以从/proc/pid/smaps获得私有的脏的和私有的干净RSS。

#6


2  

Take a look at smem. It will give you PSS information

看看smem。它会给你PSS信息。

http://www.selenic.com/smem/

http://www.selenic.com/smem/

#7


1  

for i in /proc/[0-9]*; do
  grep -q 'Private_Dirty' $i/smaps;
  if [ $? -ne 0 ]; then
    continue;
  fi;
  echo -n "${i}: ";
  awk '/Private_Dirty/ {print $2,$3}' $i/smaps |
   sed 's/ tB/*1024 gB/;s/ gB/*1024 mB/;s/ mB/*1024 kB/;s/ kB/*1024/;1!s/^/+/;' |
   tr -d '\n' |
   sed 's/$/\n/' |
   bc |
   tr -d '\n';
  echo;
done |
 sort -n -k 2

#8


0  

For a question that mentioned Freebsd, surprised no one wrote this yet :

对于一个关于Freebsd的问题,还没有人这么写:

If you want a linux style /proc/PROCESSID/status output, please do the following :

如果您想要一个linux风格/proc/PROCESSID/status输出,请执行以下操作:

mount -t linprocfs none /proc
cat /proc/PROCESSID/status

Atleast in FreeBSD 7.0, the mounting was not done by default ( 7.0 is a much older release,but for something this basic,the answer was hidden in a mailing list!)

至少在FreeBSD 7.0中,默认情况下不执行安装(7.0是一个更老的版本,但是对于一些基本的东西,答案隐藏在邮件列表中!)

#9


0  

Check it out, this is the source code of gnome-system-monitor, it thinks the memory "really used" by one process is sum(info->mem) of X Server Memory(info->memxserver) and Writable Memory(info->memwritable), the "Writable Memory" is the memory blocks which are marked as "Private_Dirty" in /proc/PID/smaps file.

检查一下,这是gnome- systemmonitor的源代码,它认为一个进程“真正使用”的内存是X服务器内存(info->memxserver)和可写内存(info->memwritable)的sum(info->mem),“可写内存”是在/proc/PID/smaps文件中标记为“Private_Dirty”的内存块。

Other than linux system, could be different way according to gnome-system-monitor code.

除了linux系统之外,根据gnome-system-monitor代码可以有不同的方式。

static void
get_process_memory_writable (ProcInfo *info)
{
    glibtop_proc_map buf;
    glibtop_map_entry *maps;

    maps = glibtop_get_proc_map(&buf, info->pid);

    gulong memwritable = 0;
    const unsigned number = buf.number;

    for (unsigned i = 0; i < number; ++i) {
#ifdef __linux__
        memwritable += maps[i].private_dirty;
#else
        if (maps[i].perm & GLIBTOP_MAP_PERM_WRITE)
            memwritable += maps[i].size;
#endif
    }

    info->memwritable = memwritable;

    g_free(maps);
}

static void
get_process_memory_info (ProcInfo *info)
{
    glibtop_proc_mem procmem;
    WnckResourceUsage xresources;

    wnck_pid_read_resource_usage (gdk_screen_get_display (gdk_screen_get_default ()),
                                  info->pid,
                                  &xresources);

    glibtop_get_proc_mem(&procmem, info->pid);

    info->vmsize    = procmem.vsize;
    info->memres    = procmem.resident;
    info->memshared = procmem.share;

    info->memxserver = xresources.total_bytes_estimate;

    get_process_memory_writable(info);

    // fake the smart memory column if writable is not available
    info->mem = info->memxserver + (info->memwritable ? info->memwritable : info->memres);
}

#1


35  

On OSX the Activity Monitor gives you actually a very good guess.

在OSX上,活动监视器会给你一个很好的猜测。

Private memory is for sure memory that is only used by your application. E.g. stack memory and all memory dynamically reserved using malloc() and comparable functions/methods (alloc method for Objective-C) is private memory. If you fork, private memory will be shared with you child, but marked copy-on-write. That means as long as a page is not modified by either process (parent or child) it is shared between them. As soon as either process modifies any page, this page is copied before it is modified. Even while this memory is shared with fork children (and it can only be shared with fork children), it is still shown as "private" memory, because in the worst case, every page of it will get modified (sooner or later) and then it is again private to each process again.

私有内存是用于确定只用于应用程序的内存。使用malloc()和类似的函数/方法(Objective-C的alloc方法)动态保留栈内存和所有内存,是私有内存。如果您使用fork,私有内存将与您共享,但是标记为copy-on-write。这意味着只要页面没有被进程(父进程或子进程)修改,就会在它们之间共享。只要进程修改了任何页面,这个页面就会在修改之前被复制。尽管这个内存是与fork子共享的(它只能与fork子共享),但它仍然被显示为“私有”内存,因为在最坏的情况下,它的每一页都将被修改(迟早),然后它又会被再次私有到每个进程。

Shared memory is either memory that is currently shared (the same pages are visible in the virtual process space of different processes) or that is likely to become shared in the future (e.g. read-only memory, since there is no reason for not sharing read-only memory). At least that's how I read the source code of some command line tools from Apple. So if you share memory between processes using mmap (or a comparable call that maps the same memory into multiple processes), this would be shared memory. However the executable code itself is also shared memory, since if another instance of your application is started there is no reason why it may not share the code already loaded in memory (executable code pages are read-only by default, unless you are running your app in a debugger). Thus shared memory is really memory used by your application, just like private one, but it might additionally be shared with another process (or it might not, but why would it not count towards your application if it was shared?)

共享内存是当前共享的内存(在不同进程的虚拟进程空间中可以看到相同的页面),或者可能在将来共享(例如只读内存,因为没有理由不共享只读内存)。至少这是我从苹果读取一些命令行工具源代码的方法。因此,如果在使用mmap(或将相同的内存映射到多个进程)的进程之间共享内存,这将是共享内存。然而,可执行代码本身也是共享内存,因为如果您的应用程序的另一个实例已经启动,那么它就没有理由不共享内存中已经加载的代码(默认情况下,可执行代码页是只读的,除非您在调试器中运行您的应用程序)。因此,共享内存实际上是您的应用程序使用的内存,就像私有内存一样,但是它可能还会与另一个进程共享(或者可能不会,但是如果它被共享了,为什么它不计算在您的应用程序中呢?)

Real memory is the amount of RAM currently "assigned" to your process, no matter if private or shared. This can be exactly the sum of private and shared, but usually it is not. Your process might have more memory assigned to it than it currently needs (this speeds up requests for more memory in the future), but that is no loss to the system. If another process needs memory and no free memory is available, before the system starts swapping, it will take that extra memory away from your process and assign it another process (which is a fast and painless operation); therefor your next malloc call might be somewhat slower. Real memory can also be smaller than private and physical memory; this is because if your process requests memory from the system, it will only receive "virtual memory". This virtual memory is not linked to any real memory pages as long as you don't use it (so malloc 10 MB of memory, use only one byte of it, your process will get only a single page, 4096 byte, of memory assigned - the rest is only assigned if you actually ever need it). Further memory that is swapped may not count towards real memory either (not sure about this), but it will count towards shared and private memory.

真正的内存是当前“分配”到您的进程中的RAM的数量,无论是私有的还是共享的。这可以是私有和共享的总和,但通常不是。您的进程可能会有更多的内存分配给它,而不是当前的需求(这会加快请求,以便将来有更多的内存),但是这对系统来说是没有损失的。如果另一个进程需要内存,并且没有空闲内存可用,在系统开始交换之前,它将从您的进程中移除额外的内存并分配另一个进程(这是一个快速且无痛的操作);因此,您的下一个malloc调用可能会稍微慢一些。实际内存也可以小于私有内存和物理内存;这是因为如果您的进程请求系统内存,它将只接收“虚拟内存”。这个虚拟内存不与任何真正的内存页面,只要你不使用它(所以malloc 10 MB的内存,只使用一个字节,您的流程将会只有一个页面,4096字节的内存分配,其余的只是如果你真的需要它)。交换的内存可能不计入实际内存(不确定这一点),但它将计算共享内存和私有内存。

Virtual memory is the sum of all address blocks that are consider valid in your apps process space. These addresses might be linked to physical memory (that is again private or shared), or they might not, but in that case they will be linked to physical memory as soon as you use the address. Accessing memory addresses outside of the known addresses will cause a SIGBUS and your app will crash. When memory is swapped, the virtual address space for this memory remains valid and accessing those addresses causes memory to be swapped back in.

虚拟内存是在你的应用程序空间中被认为有效的所有地址块的总和。这些地址可能与物理内存(再次是私有的或共享的)相关联,或者它们可能不链接,但是在这种情况下,当您使用地址时,它们将与物理内存联系起来。访问已知地址之外的内存地址将导致SIGBUS,而您的应用程序将崩溃。当内存被交换时,此内存的虚拟地址空间仍然有效,并且访问这些地址将导致内存被交换回。

Conclusion:
If your app does not explicitly or implicitly use shared memory, private memory is the amount of memory your app needs because of the stack size (or sizes if multithreaded) and because of the malloc() calls you made for dynamic memory. You don't have to care a lot for shared or real memory in that case.

结论:如果您的应用程序没有显式地或隐式地使用共享内存,那么私有内存就是您的应用程序需要的内存数量,因为栈大小(或者是多线程的大小),以及由于malloc()调用您为动态内存所做的调用。在这种情况下,您不必关心共享或实际内存。

If your app uses shared memory, and this includes a graphical UI, where memory is shared between your application and the WindowServer for example, then you might have a look at shared memory as well. A very high shared memory number may mean you have too many graphical resources loaded in memory at the moment.

如果你的应用程序使用共享内存,这包括一个图形用户界面,在你的应用程序和windows服务器之间共享内存,那么你也可以查看共享内存。一个非常高的共享内存号可能意味着您在内存中有太多的图形资源。

Real memory is of little interest for app development. If it is bigger than the sum of shared and private, then this means nothing other than that the system is lazy at taken memory away from your process. If it is smaller, then your process has requested more memory than it actually needed, which is not bad either, since as long as you don't use all of the requested memory, you are not "stealing" memory from the system. If it is much smaller than the sum of shared and private, you may only consider to request less memory where possible, as you are a bit over-requesting memory (again, this is not bad, but it tells me that your code is not optimized for minimal memory usage and if it is cross platform, other platforms may not have such a sophisticated memory handling, so you may prefer to alloc many small blocks instead of a few big ones for example, or free memory a lot sooner, and so on).

实际内存对应用程序开发没有多大兴趣。如果它大于共享和私有的总和,那么这就意味着系统很懒,将内存从进程中删除。如果它更小,那么您的进程请求的内存比实际需要的要多,这也不坏,因为只要您不使用所有被请求的内存,就不会从系统中“窃取”内存。如果它是远小于共享和私有的总和,你可能只考虑请求更少内存在可能的情况下,当你有点over-requesting内存(这并不坏,但是它告诉我,你的代码并不是最小的优化内存使用,如果它是跨平台的,其他平台可能没有这样一个复杂的内存处理,所以你可能喜欢alloc许多小块而不是几大的例如,或空闲内存很多早,等等)。

If you are still not happy with all that information, you can get even more information. Open a terminal and run:

如果你仍然对这些信息不满意,你可以得到更多的信息。打开终端并运行:

sudo vmmap <pid>

where is the process ID of your process. This will show you statistics for EVERY block of memory in your process space with start and end address. It will also tell you where this memory came from (A mapped file? Stack memory? Malloc'ed memory? A __DATA or __TEXT section of your executable?), how big it is in KB, the access rights and whether it is private, shared or copy-on-write. If it is mapped from a file, it will even give you the path to the file.

您的进程的进程ID在哪里。这将向您显示进程空间中带有起始地址和结束地址的每个内存块的统计信息。它还会告诉您这个内存来自哪里(一个映射文件?栈内存?分配的内存?您的可执行文件的__DATA或__TEXT部分?),它在KB中有多大,访问权限以及它是私有的、共享的还是复制的。如果它从一个文件映射,它甚至会给你文件的路径。

If you want only "actual" RAM usage, use

如果您只需要“实际”RAM的使用,请使用。

sudo vmmap -resident <pid>

Now it will show for every memory block how big the memory block is virtually and how much of it is really currently present in physical memory.

现在它将显示每个内存块的大小,内存块的大小,以及它当前在物理内存中有多少。

At the end of each dump is also an overview table with the sums of different memory types. This table looks like this for Firefox right now on my system:

在每个转储的末尾也是一个带有不同内存类型和的概述表。这个表格现在在我的系统上是这样的:

REGION TYPE             [ VIRTUAL/RESIDENT]
===========             [ =======/========]
ATS (font support)      [   33.8M/   2496K]
CG backing stores       [   5588K/   5460K]
CG image                [     20K/     20K]
CG raster data          [    576K/    576K]
CG shared images        [   2572K/   2404K]
Carbon                  [   1516K/   1516K]
CoreGraphics            [      8K/      8K]
IOKit                   [  256.0M/      0K]
MALLOC                  [  256.9M/  247.2M]
Memory tag=240          [      4K/      4K]
Memory tag=242          [     12K/     12K]
Memory tag=243          [      8K/      8K]
Memory tag=249          [    156K/     76K]
STACK GUARD             [  101.2M/   9908K]
Stack                   [   14.0M/    248K]
VM_ALLOCATE             [   25.9M/   25.6M]
__DATA                  [   6752K/   3808K]
__DATA/__OBJC           [     28K/     28K]
__IMAGE                 [   1240K/    112K]
__IMPORT                [    104K/    104K]
__LINKEDIT              [   30.7M/   3184K]
__OBJC                  [   1388K/   1336K]
__OBJC/__DATA           [     72K/     72K]
__PAGEZERO              [      4K/      0K]
__TEXT                  [  108.6M/   63.5M]
__UNICODE               [    536K/    512K]
mapped file             [  118.8M/   50.8M]
shared memory           [    300K/    276K]
shared pmap             [   6396K/   3120K]

What does this tell us? E.g. the Firefox binary and all library it loads have 108 MB data together in their __TEXT sections, but currently only 63 MB of those are currently resident in memory. The font support (ATS) needs 33 MB, but only about 2.5 MB are really in memory. It uses a bit over 5 MB CG backing stores, CG = Core Graphics, those are most likely window contents, buttons, images and other data that is cached for fast drawing. It has requested 256 MB via malloc calls and currently 247 MB are really in mapped to memory pages. It has 14 MB space reserved for stacks, but only 248 KB stack space is really in use right now.

这告诉我们什么?例如,Firefox二进制文件和所有它装载的所有库在它们的__TEXT部分中都有108 MB的数据,但是目前只有63 MB的数据是驻留在内存中的。字体支持(ATS)需要33 MB,但只有大约2.5 MB内存。它使用了超过5mb的CG支持存储,CG =核心图形,这些是最可能的窗口内容,按钮,图像和其他缓存的快速绘图数据。它通过malloc调用请求256 MB,而当前的247 MB确实映射到内存页面。它预留了14 MB空间用于堆栈,但是现在只有248 KB的堆栈空间正在使用。

vmmap also has a good summary above the table

vmmap在表上也有一个很好的总结。

ReadOnly portion of Libraries: Total=139.3M resident=66.6M(48%) swapped_out_or_unallocated=72.7M(52%)
Writable regions: Total=595.4M written=201.8M(34%) resident=283.1M(48%) swapped_out=0K(0%) unallocated=312.3M(52%)

And this shows an interesting aspect of the OS X: For read only memory it plays no role if it is swapped out or simply unallocated; there is only resident and not resident. For writable memory this makes a difference (in my case 52% of all requested memory has never been used and is such unallocated, 0% of memory has been swapped out to disk)

这显示了OS X的一个有趣的方面:对于只读内存,如果它被换出或只是没有分配,它就不会起作用;只有居民而非居民。对于可写的内存,这是有区别的(在我的情况下,所有请求的内存中有52%从未被使用过,并且是这样未分配的,内存的0%已被交换到磁盘)

#2


8  

On Linux, you may want the PSS (proportional set size) numbers in /proc/self/smaps. A mapping's PSS is its RSS divided by the number of processes which are using that mapping.

在Linux上,您可能想要PSS(比例集大小)在/proc/self/smaps中的数字。映射的PSS是它的RSS,除以使用该映射的进程的数量。

#3


4  

Top knows how to do this. It shows VIRT, RES and SHR by default on Debian Linux. VIRT = SWAP + RES. RES = CODE + DATA. SHR is the memory that may be shared with another process (shared library or other memory.)

Top知道怎么做。它在Debian Linux上默认显示VIRT、RES和SHR。交换+ RES =代码+数据。SHR是可以与另一个进程共享的内存(共享库或其他内存)。

Also, 'dirty' memory is merely RES memory that has been used, and/or has not been swapped.

另外,“脏”内存仅仅是被使用过的内存,并且/或没有被交换。

It can be hard to tell, but the best way to understand is to look at a system that isn't swapping. Then, RES - SHR is the process exclusive memory. However, that's not a good way of looking at it, because you don't know that the memory in SHR is being used by another process. It may represent unwritten shared object pages that are only used by the process.

很难说,但最好的理解方式是看一个不交换的系统。然后,RES - SHR是进程独占内存。但是,这并不是一个好的方法,因为您不知道SHR中的内存正在被另一个进程使用。它可能表示仅由进程使用的未写的共享对象页。

#4


4  

You really can't.

你真的不能。

I mean, shared memory between processes... are you going to count it, or not. If you don't count it, you are wrong; the sum of all processes' memory usage is not going to be the total memory usage. If you count it, you are going to count it twice- the sum's not going to be correct.

我是说,进程之间共享内存…你要数一下吗?如果你不去数它,那你就错了;所有进程内存使用的总和不会是总内存使用量。如果你数一数,你就会数一遍,总数不会是正确的。

Me, I'm happy with RSS. And knowing you can't really rely on it completely...

我对RSS很满意。知道你不能完全依赖它……

#5


4  

You can get private dirty and private clean RSS from /proc/pid/smaps

您可以从/proc/pid/smaps获得私有的脏的和私有的干净RSS。

#6


2  

Take a look at smem. It will give you PSS information

看看smem。它会给你PSS信息。

http://www.selenic.com/smem/

http://www.selenic.com/smem/

#7


1  

for i in /proc/[0-9]*; do
  grep -q 'Private_Dirty' $i/smaps;
  if [ $? -ne 0 ]; then
    continue;
  fi;
  echo -n "${i}: ";
  awk '/Private_Dirty/ {print $2,$3}' $i/smaps |
   sed 's/ tB/*1024 gB/;s/ gB/*1024 mB/;s/ mB/*1024 kB/;s/ kB/*1024/;1!s/^/+/;' |
   tr -d '\n' |
   sed 's/$/\n/' |
   bc |
   tr -d '\n';
  echo;
done |
 sort -n -k 2

#8


0  

For a question that mentioned Freebsd, surprised no one wrote this yet :

对于一个关于Freebsd的问题,还没有人这么写:

If you want a linux style /proc/PROCESSID/status output, please do the following :

如果您想要一个linux风格/proc/PROCESSID/status输出,请执行以下操作:

mount -t linprocfs none /proc
cat /proc/PROCESSID/status

Atleast in FreeBSD 7.0, the mounting was not done by default ( 7.0 is a much older release,but for something this basic,the answer was hidden in a mailing list!)

至少在FreeBSD 7.0中,默认情况下不执行安装(7.0是一个更老的版本,但是对于一些基本的东西,答案隐藏在邮件列表中!)

#9


0  

Check it out, this is the source code of gnome-system-monitor, it thinks the memory "really used" by one process is sum(info->mem) of X Server Memory(info->memxserver) and Writable Memory(info->memwritable), the "Writable Memory" is the memory blocks which are marked as "Private_Dirty" in /proc/PID/smaps file.

检查一下,这是gnome- systemmonitor的源代码,它认为一个进程“真正使用”的内存是X服务器内存(info->memxserver)和可写内存(info->memwritable)的sum(info->mem),“可写内存”是在/proc/PID/smaps文件中标记为“Private_Dirty”的内存块。

Other than linux system, could be different way according to gnome-system-monitor code.

除了linux系统之外,根据gnome-system-monitor代码可以有不同的方式。

static void
get_process_memory_writable (ProcInfo *info)
{
    glibtop_proc_map buf;
    glibtop_map_entry *maps;

    maps = glibtop_get_proc_map(&buf, info->pid);

    gulong memwritable = 0;
    const unsigned number = buf.number;

    for (unsigned i = 0; i < number; ++i) {
#ifdef __linux__
        memwritable += maps[i].private_dirty;
#else
        if (maps[i].perm & GLIBTOP_MAP_PERM_WRITE)
            memwritable += maps[i].size;
#endif
    }

    info->memwritable = memwritable;

    g_free(maps);
}

static void
get_process_memory_info (ProcInfo *info)
{
    glibtop_proc_mem procmem;
    WnckResourceUsage xresources;

    wnck_pid_read_resource_usage (gdk_screen_get_display (gdk_screen_get_default ()),
                                  info->pid,
                                  &xresources);

    glibtop_get_proc_mem(&procmem, info->pid);

    info->vmsize    = procmem.vsize;
    info->memres    = procmem.resident;
    info->memshared = procmem.share;

    info->memxserver = xresources.total_bytes_estimate;

    get_process_memory_writable(info);

    // fake the smart memory column if writable is not available
    info->mem = info->memxserver + (info->memwritable ? info->memwritable : info->memres);
}