在 linux 中观察共享映射文件内存
Observing shared mapped file memory in linux
我正在使用 mmap
系统调用加载文件内存以供其他几个进程读取(使用标志 MAP_SHARED
和 MAP_POPULATE
提前加载所有内存。)。
检查进程内存消耗似乎忽略了映射文件内存共享的事实。根据 ps -aux
命令,每个进程内存使用包含内存中的整个映射文件。
有没有办法区分共享进程内存和私有进程内存?
即使内存是物理共享的,每个进程都有自己的虚拟内存映射,并且将 "consume" 独立寻址 space 即使映射相同的区域 - 你可以在 VSIZE 中看到柱子。在任何情况下(即使在 malloc()
之后)内核都会为每个进程保留一个独立的寻址 space,但不会立即在 backing store 中分配等效的页面].
一旦你开始reading/writing分配的内存,虚拟页面就被分配给相应的backing store:驻留集相应增加。
如果您只是阅读,这些页面是 "clean",如果您写入它们,则这些页面是 "dirty",直到它们不同步。 (参见 /proc/PID/smaps
、/proc documentation、man pmap
:此工具可让您区分共享内存和私有内存、脏页和干净页)
MAP_POPULATE
选项立即预分配所有页面。如果映射是 MAP_PRIVATE
,则允许页面保持脏状态,直到它们未明确与 msync()
同步。脏页缓存在 RAM 中,实际上,只要您使用更多页面,可用的系统内存就会减少,并带有私有映射。
另一方面,使用 MAP_SHARED
,您需要内核与 [= 保持虚拟页面同步(即页面必须尽快干净,即使是异步的) 127=]后备存储.
但是对于映射文件,后备存储不是内存,而是文件——因为它是交换 space。所以你有一个奇怪的效果,即映射文件被计为常驻集。
观察/proc/PID/status
的内容可以验证:
VmRSS size of memory portions. It contains the three
following parts (VmRSS = RssAnon + RssFile + RssShmem)
RssAnon size of resident anonymous memory
RssFile size of resident file mappings
RssShmem size of resident shmem memory (includes SysV shm,
mapping of tmpfs and shared anonymous mappings)
VmRSS 就是通常报告为 RSS 的内容。
在这种情况下,RSS 不计算物理内存,而是计算文件映射:请求 MAP_SHARED
时,系统总内存大部分不受影响,因为几乎没有页面被缓存(缓存,脏页将被计入RssAnon
)。它们必须尽快刷新到共享 后备存储 (文件)。
正如您正确观察到的那样,RSS 每个进程都计为一次,即使是共享的也是如此。您可以在 /proc/PID/smaps
中找到另一个计数器 PSS(比例设置大小)- 也请参阅此答案:
What does pss mean in /proc/pid/smaps
The "proportional set size" (PSS) of a process is the count of pages it has in memory, where each page is divided by the number of processes sharing it. So if a process has 1000 pages all to itself, and 1000 shared with one other process, its PSS will be 1500
请注意:您可以使用 MAP_SHARED|MAP_POPULATE
仅使用 tmpfs
共享内存 - 否则您将使用基于文件的共享。如果您正在寻找 IPC 共享内存,请查看 shmget()
。
测试
我用一个小程序验证了我的陈述,它从一个带有不同标志的文件映射了 2 GB,然后用 memset()
.
写了 1/3 的页面
MAP_PRIVATE
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 15767 0.5 4.1 2004216 666944 pts/1 S+ 12:54 0:00 ./mm 1
来自 /proc/PID/smaps
:
7f143e5ec000-7f14b870c000 rw-p 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 666668 kB
Pss: 666668 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 666668 kB
Referenced: 666668 kB
Anonymous: 666668 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac sd
来自 /proc/PID/status
:
VmRSS: 666944 kB
RssAnon: 666560 kB
RssFile: 384 kB
RssShmem: 0 kB
MAP_PRIVATE | MAP_POPULATE
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 17045 31.0 12.3 2004216 2000412 pts/1 S+ 13:01 0:01 ./mm 2
来自 /proc/PID/smaps
:
7f14aa983000-7f1524aa3000 rw-p 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 2000000 kB
Pss: 2000000 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 2000000 kB
Referenced: 2000000 kB
Anonymous: 2000000 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac sd
来自 /proc/PID/status
:
VmRSS: 2000412 kB
RssAnon: 2000032 kB
RssFile: 380 kB
RssShmem: 0 kB
MAP_SHARED
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 17670 18.0 4.1 2004216 666944 pts/1 S+ 13:06 0:00 ./mm 3
来自 /proc/PID/smaps
:
7f01db018000-7f0255138000 rw-s 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 666668 kB
Pss: 666668 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 666668 kB
Private_Dirty: 0 kB
Referenced: 666668 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr sh mr mw me ms sd
来自 /proc/PID/status
:
VmRSS: 666944 kB
RssAnon: 96 kB
RssFile: 666848 kB
RssShmem: 0 kB
MAP_SHARED | MAP_POPULATE
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 18259 16.1 12.3 2004216 2000480 pts/1 S+ 13:10 0:00 ./mm 4
来自 /proc/PID/smaps
:
7ff0d020b000-7ff14a32b000 rw-s 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 2000000 kB
Pss: 2000000 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 2000000 kB
Private_Dirty: 0 kB
Referenced: 2000000 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr sh mr mw me ms sd
来自 /proc/PID/status
:
VmRSS: 2000480 kB
RssAnon: 96 kB
RssFile: 2000384 kB
RssShmem: 0 kB
MAP_SHARED | MAP_POPULATE,两个实例
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 18259 0.1 12.3 2004216 2000480 pts/1 S 13:10 0:00 ./mm 4
xxxx 19521 5.8 12.3 2004216 2000480 pts/1 S+ 13:19 0:00 ./mm 4
来自 /proc/PID/smaps
,仅第一个 PID:
7ff0d020b000-7ff14a32b000 rw-s 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 2000000 kB
Pss: 1000000 kB
Shared_Clean: 2000000 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 2000000 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr sh mr mw me ms sd
来自 /proc/PID/status
:
VmRSS: 2000480 kB
RssAnon: 96 kB
RssFile: 2000384 kB
RssShmem: 0 kB
我正在使用 mmap
系统调用加载文件内存以供其他几个进程读取(使用标志 MAP_SHARED
和 MAP_POPULATE
提前加载所有内存。)。
检查进程内存消耗似乎忽略了映射文件内存共享的事实。根据 ps -aux
命令,每个进程内存使用包含内存中的整个映射文件。
有没有办法区分共享进程内存和私有进程内存?
即使内存是物理共享的,每个进程都有自己的虚拟内存映射,并且将 "consume" 独立寻址 space 即使映射相同的区域 - 你可以在 VSIZE 中看到柱子。在任何情况下(即使在 malloc()
之后)内核都会为每个进程保留一个独立的寻址 space,但不会立即在 backing store 中分配等效的页面].
一旦你开始reading/writing分配的内存,虚拟页面就被分配给相应的backing store:驻留集相应增加。
如果您只是阅读,这些页面是 "clean",如果您写入它们,则这些页面是 "dirty",直到它们不同步。 (参见 /proc/PID/smaps
、/proc documentation、man pmap
:此工具可让您区分共享内存和私有内存、脏页和干净页)
MAP_POPULATE
选项立即预分配所有页面。如果映射是 MAP_PRIVATE
,则允许页面保持脏状态,直到它们未明确与 msync()
同步。脏页缓存在 RAM 中,实际上,只要您使用更多页面,可用的系统内存就会减少,并带有私有映射。
另一方面,使用 MAP_SHARED
,您需要内核与 [= 保持虚拟页面同步(即页面必须尽快干净,即使是异步的) 127=]后备存储.
但是对于映射文件,后备存储不是内存,而是文件——因为它是交换 space。所以你有一个奇怪的效果,即映射文件被计为常驻集。
观察/proc/PID/status
的内容可以验证:
VmRSS size of memory portions. It contains the three
following parts (VmRSS = RssAnon + RssFile + RssShmem)
RssAnon size of resident anonymous memory
RssFile size of resident file mappings
RssShmem size of resident shmem memory (includes SysV shm,
mapping of tmpfs and shared anonymous mappings)
VmRSS 就是通常报告为 RSS 的内容。
在这种情况下,RSS 不计算物理内存,而是计算文件映射:请求 MAP_SHARED
时,系统总内存大部分不受影响,因为几乎没有页面被缓存(缓存,脏页将被计入RssAnon
)。它们必须尽快刷新到共享 后备存储 (文件)。
正如您正确观察到的那样,RSS 每个进程都计为一次,即使是共享的也是如此。您可以在 /proc/PID/smaps
中找到另一个计数器 PSS(比例设置大小)- 也请参阅此答案:
What does pss mean in /proc/pid/smaps
The "proportional set size" (PSS) of a process is the count of pages it has in memory, where each page is divided by the number of processes sharing it. So if a process has 1000 pages all to itself, and 1000 shared with one other process, its PSS will be 1500
请注意:您可以使用 MAP_SHARED|MAP_POPULATE
仅使用 tmpfs
共享内存 - 否则您将使用基于文件的共享。如果您正在寻找 IPC 共享内存,请查看 shmget()
。
测试
我用一个小程序验证了我的陈述,它从一个带有不同标志的文件映射了 2 GB,然后用 memset()
.
MAP_PRIVATE
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 15767 0.5 4.1 2004216 666944 pts/1 S+ 12:54 0:00 ./mm 1
来自 /proc/PID/smaps
:
7f143e5ec000-7f14b870c000 rw-p 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 666668 kB
Pss: 666668 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 666668 kB
Referenced: 666668 kB
Anonymous: 666668 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac sd
来自 /proc/PID/status
:
VmRSS: 666944 kB
RssAnon: 666560 kB
RssFile: 384 kB
RssShmem: 0 kB
MAP_PRIVATE | MAP_POPULATE
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 17045 31.0 12.3 2004216 2000412 pts/1 S+ 13:01 0:01 ./mm 2
来自 /proc/PID/smaps
:
7f14aa983000-7f1524aa3000 rw-p 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 2000000 kB
Pss: 2000000 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 2000000 kB
Referenced: 2000000 kB
Anonymous: 2000000 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr mr mw me ac sd
来自 /proc/PID/status
:
VmRSS: 2000412 kB
RssAnon: 2000032 kB
RssFile: 380 kB
RssShmem: 0 kB
MAP_SHARED
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 17670 18.0 4.1 2004216 666944 pts/1 S+ 13:06 0:00 ./mm 3
来自 /proc/PID/smaps
:
7f01db018000-7f0255138000 rw-s 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 666668 kB
Pss: 666668 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 666668 kB
Private_Dirty: 0 kB
Referenced: 666668 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr sh mr mw me ms sd
来自 /proc/PID/status
:
VmRSS: 666944 kB
RssAnon: 96 kB
RssFile: 666848 kB
RssShmem: 0 kB
MAP_SHARED | MAP_POPULATE
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 18259 16.1 12.3 2004216 2000480 pts/1 S+ 13:10 0:00 ./mm 4
来自 /proc/PID/smaps
:
7ff0d020b000-7ff14a32b000 rw-s 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 2000000 kB
Pss: 2000000 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 2000000 kB
Private_Dirty: 0 kB
Referenced: 2000000 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr sh mr mw me ms sd
来自 /proc/PID/status
:
VmRSS: 2000480 kB
RssAnon: 96 kB
RssFile: 2000384 kB
RssShmem: 0 kB
MAP_SHARED | MAP_POPULATE,两个实例
ps -u
输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
xxxx 18259 0.1 12.3 2004216 2000480 pts/1 S 13:10 0:00 ./mm 4
xxxx 19521 5.8 12.3 2004216 2000480 pts/1 S+ 13:19 0:00 ./mm 4
来自 /proc/PID/smaps
,仅第一个 PID:
7ff0d020b000-7ff14a32b000 rw-s 00000000 fd:00 201562609 /home/xxxx/test/mm.dat
Size: 2000000 kB
Rss: 2000000 kB
Pss: 1000000 kB
Shared_Clean: 2000000 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 2000000 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
VmFlags: rd wr sh mr mw me ms sd
来自 /proc/PID/status
:
VmRSS: 2000480 kB
RssAnon: 96 kB
RssFile: 2000384 kB
RssShmem: 0 kB