在OSX上,活动监视器实际上为您提供了一个很好的猜测。
专用内存可以确保仅由您的应用程序使用的内存。 例如。 堆栈内存和使用malloc()和类似功能/方法(Objective-C的alloc方法)动态保留的所有内存都是私有内存。 如果您分叉,则私有内存将与您的孩子共享,但标记为写时复制。 这意味着只要页面没有被任何进程(父进程或子进程)修改,它们就可以在它们之间共享。 只要任一进程修改了任何页面,该页面就会在修改之前被复制。 即使此内存与fork子代共享(并且只能与fork子代共享),它仍显示为“私有”内存,因为在最坏的情况下,它的每一页都会被修改(很快或以后),并且 然后它又是每个过程的私有对象。
共享内存既可以是当前共享的内存(在不同进程的虚拟进程空间中可以看到相同的页面),也可以是将来可能共享的内存(例如只读内存,因为没有理由不共享读取的内存) -仅内存)。至少这就是我从Apple那里读取某些命令行工具的源代码的方式。因此,如果您使用mmap在进程之间共享内存(或将同一内存映射到多个进程的类似调用),则这将是共享内存。但是,可执行代码本身也是共享内存,因为如果启动了应用程序的另一个实例,则没有理由不共享已加载到内存中的代码(默认情况下,可执行代码页为只读,除非您正在运行调试器中的应用程序)。因此,共享内存实际上是您的应用程序使用的内存,就像私有内存一样,但是它可能另外与另一个进程共享(或者可能不是,但是,如果共享了,为什么不计入您的应用程序?)
实际内存是当前“分配”给您的进程的RAM数量,无论是私有的还是共享的。这可以恰好是私有和共享的总和,但通常不是。为您的进程分配的内存可能比当前所需的内存更多(这会加快将来对更多内存的请求),但这不会给系统带来损失。如果另一个进程需要内存而没有可用内存,则在系统开始交换之前,它将把多余的内存从您的进程中移走,并为其分配另一个进程(这是一种快速而轻松的操作);因此,您的下一个malloc调用可能会比较慢。实际内存也可以小于私有内存和物理内存。这是因为,如果您的进程从系统请求内存,它将仅接收“虚拟内存”。只要您不使用此虚拟内存,它就不会链接到任何实际内存页面(因此malloc 10 MB内存,仅使用一个字节,您的进程将只分配一个页面,即4096字节的内存) -仅在您实际需要时才分配其余部分)。交换的其他内存也可能不会计入实际内存(对此不确定),但是会计入共享内存和私有内存。
虚拟内存是在您的应用进程空间中被认为有效的所有地址块的总和。 这些地址可能链接到物理内存(又是私有的或共享的),也可能没有,但是在这种情况下,一旦您使用该地址,它们就会链接到物理内存。 访问已知地址之外的内存地址将导致SIGBUS,并且您的应用程序将崩溃。 交换内存时,该内存的虚拟地址空间保持有效,访问这些地址将导致内存被交换回。
结论:
如果您的应用程序没有显式或隐式使用共享内存,则由于堆栈大小(或多线程大小)以及由于您对动态内存进行的malloc()调用,专用内存是应用程序需要的内存量。 在这种情况下,您不必太在意共享或实际内存。
如果您的应用程序使用共享内存,并且其中包括一个图形用户界面,例如,您的应用程序和WindowServer之间共享内存,那么您也可以查看共享内存。 很高的共享内存数量可能意味着您当前在内存中加载了太多的图形资源。
实际内存对于应用程序开发几乎没有兴趣。 如果它大于共享和私有总和,则意味着系统懒于从进程中占用内存。 如果较小,则您的进程所请求的内存超过了实际需要的内存,这也不错,因为只要您不使用所有请求的内存,就不会从系统“窃取”内存。 如果它比共享和私有的总和小得多,则您可能只考虑在可能的情况下请求较少的内存,因为您有点超额使用了内存(同样,这还不错,但这告诉我您的代码不是 已针对最小化的内存使用进行了优化,并且如果它是跨平台的,则其他平台可能没有如此复杂的内存处理,因此您可能更喜欢分配许多小块而不是一些大块,或者更快地释放内存,等等 上)。
如果您对所有这些信息仍然不满意,则可以获得更多信息。 打开一个终端并运行:
sudo vmmap <pid>
您的流程的流程ID在哪里。 这将为您显示进程空间中每个内存块的统计信息,包括开始和结束地址。 它还会告诉您该内存的来源(映射文件?堆栈内存?Malloc的内存?可执行文件的__DATA或__TEXT部分?),KB大小,访问权限以及是否为私有, 共享或写时复制。 如果是从文件映射的,它甚至会为您提供文件的路径。
如果只希望“实际” RAM使用,请使用
sudo vmmap -resident <pid>
现在,它将为每个内存块显示虚拟内存块的大小以及当前物理内存中实际存在的内存块数量。
每个转储末尾还有一个概览表,其中包含不同内存类型的总和。 该表目前在我的系统上适用于Firefox:
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]
这告诉我们什么? 例如。 Firefox二进制文件及其加载的所有库的__TEXT节中总共有108 MB的数据,但是目前其中只有63 MB驻留在内存中。 字体支持(ATS)需要33 MB,但实际上只有约2.5 MB的内存。 它使用了超过5 MB的CG后备存储,CG =核心图形,这很可能是窗口内容,按钮,图像和其他数据,它们被缓存以用于快速绘制。 它已通过malloc调用请求了256 MB,当前247 MB实际上已映射到内存页面。 它为堆栈保留了14 MB的空间,但是现在实际上仅使用248 KB的堆栈空间。
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%)
这显示了OS X的一个有趣的方面:对于只读内存,如果换出内存或只是简单地未分配内存,它将不起作用。 只有居民而没有居民。 对于可写内存,这有所作为(在我的情况下,从未使用过所有请求的内存的52%,并且这种内存未分配,因此0%的内存已换出到磁盘)