了解Linux/proc/id/maps

sim*_*mon 143 linux embedded

我试图了解我的嵌入式Linux应用程序的内存使用情况.该/proc/pid/maps实用程序/文件似乎是看到细节的好资源.不幸的是,我不理解所有列和条目.

/proc/pid/maps实用程序/文件是否有良好的资源/文档?

匿名inode 0条目是什么意思?这些似乎是一些较大的内存段.

Jay*_*rod 245

每行/proc/$PID/maps描述进程或线程中连续虚拟内存的区域.每行都有以下字段:

address           perms offset  dev   inode   pathname
08048000-08056000 r-xp 00000000 03:0c 64593   /usr/sbin/gpm
Run Code Online (Sandbox Code Playgroud)
  • address - 这是进程地址空间中区域的起始和结束地址
  • permissions - 描述如何访问区域中的页面.有四种不同的权限:读取,写入,执行和共享.如果禁用读/写/执行,-则会出现a而不是r/ w/ x.如果某个区域未共享,则为私有区域,因此p将显示a而不是s.如果进程尝试以不允许的方式访问内存,则会生成分段错误.可以使用mprotect系统调用更改权限.
  • offset - 如果区域是从文件(使用mmap)映射的,则这是映射开始的文件中的偏移量.如果内存未从文件映射,则它只是0.
  • device - 如果区域是从文件映射的,则这是文件所在的主要和次要设备编号(十六进制).
  • inode - 如果区域是从文件映射的,则这是文件编号.
  • pathname - 如果区域是从文件映射的,则这是文件的名称.匿名映射区域的此字段为空.此外还有一些与喜欢的名字特殊的区域[heap],[stack][vdso].[vdso]代表虚拟动态共享对象.它被系统调用用于切换到内核模式.这是一篇关于它的好文章.

你可能会注意到很多匿名区域.这些通常由mmap任何文件创建,但不附加到任何文件.它们用于许多杂项内容,例如共享内存或未在堆上分配的缓冲区.例如,我认为pthread库使用匿名映射区域作为新线程的堆栈.

  • 是的,pthreads正在为一个堆栈分配8Mb块,其中一个较小的部分用于堆栈溢出检测(我认为).因此,默认情况下,每个pthread都会创建一个8Mb的inode 0内存区域和4Kb的inode 0区域. (4认同)
  • 不幸的是,该链接已死。 (3认同)

Xeo*_*eor 9

内存映射不仅用于将文件映射到内存,还是从内核请求RAM的工具.这些是inode 0条目 - 您的堆栈,堆,bss段等


Kal*_*ert 6

虽然问题专门提到了嵌入式系统,但标题只提到了proc/<pid>/maps,这对于理解“正常”程序也非常有用。在这个更广泛的上下文中,重要的是要认识到由分配的内存malloc()可以最终位于堆中或任意数量的匿名内存段中。因此,大块匿名内存很可能来自malloc().

\n

更准确地说,as指/proc/<pid>/maps[heap]是分配给静态变量的内存(称为BSS 段)和称为“程序中断”的地址之间的连续区域(见下图)。最初,该区域是空的并且没有堆。当被调用时,它可以通过系统调用\xe2\x80\x94要求内核\xe2\x80\x94移动程序中断来malloc()创建/扩展堆。brk()同样,free()如果与程序中断相邻的所有地址都不再使用,则可以缩小堆。

\n

malloc()然而,移动程序中断并不是可以为自己腾出更多空间的唯一方法。它还可以通过系统调用\xe2\x80\x94要求内核mmap()\xe2\x80\x94在堆栈和堆之间的某个位置保留一块空间(见下图)。以这种方式分配的内存显示/proc/<pid>/maps为问题中提到的“匿名 inode 0 条目”。

\n

虚拟内存图\n图片来源

\n

值得对mmap()系统调用进行一些详细说明。可以创建四种内存映射mmap(),每种内存映射都有不同的用途。首先,内存可以与某个文件的内容绑定,也可以不绑定。后者被称为“匿名”地图。其次,内存可以是“私有”的,也可以是“共享的”。私有意味着一个进程所做的更改对任何其他进程都是不可见的;这通常以一种惰性且高效的方式实现,称为“写时复制”。共享意味着每个进程都可以访问相同的底层物理内存。以下是我所知道的每种内存映射的用途:

\n\n

回到/proc/<pid>/maps,您可以通过查看“pathname”和“perms”列来找出每行描述的内存映射类型。(这些列名称来自内核文档)。对于文件映射,“路径名”列将保存正在映射的文件的实际路径。对于匿名地图,“路径名”列将为空。还有一些特殊的路径名,例如[heap][stack]。对于私有和共享地图,“perms”列将分别包含ps标志。

\n

当前malloc()用于brk()小分配和mmap()大分配的实现。在堆上分配少量内存是有意义的,因为通常可以找到必要的空间,而不必进行昂贵的系统调用(例如,通过重用以前释放的空间)。然而,大量分配存在永远不会被释放回操作系统的风险。考虑一下如果您要在堆上进行大量分配,然后进行一堆小分配,会发生什么情况。即使在释放大分配之后,程序中断也无法移回,直到所有小分配也被释放为止。这个简单的示例假设分配按顺序进入堆,这是一种幼稚的方法,但它说明了堆如何使将内存释放回操作系统变得更加困难。

\n

这是相关部分man malloc

\n
\n

通常,malloc() 从堆中分配内存,并使用 sbrk(2) 根据需要调整堆的大小。当分配大于 MMAP_THRESHOLD 字节的内存块时,glibc malloc() 实现会使用 mmap(2) 将内存分配为私有匿名映射。MMAP_THRESHOLD 默认情况下为 128 kB,但可以使用 mallopt(3) 进行调整。在 Linux 4.7 之前,使用 mmap(2) 执行的分配不受 RLIMIT_DATA 资源限制的影响;从 Linux 4.7 开始,对于使用 mmap(2) 执行的分配也强制执行此限制。

\n
\n

总之,如果您的程序使用malloc(),则malloc()可能负责许多映射到虚拟内存并由 报告的大型匿名段/proc/<pid>/maps

\n
\n

买者自负:我在这里写的几乎所有内容都是我今天才学到的,所以请持保留态度。也就是说,我发现以下资源链接对于理解所有这些非常有帮助:

\n\n


cah*_*yaz 5

请检查:http : //man7.org/linux/man-pages/man5/proc.5.html

address           perms offset  dev   inode       pathname
00400000-00452000 r-xp 00000000 08:02 173521      /usr/bin/dbus-daemon
Run Code Online (Sandbox Code Playgroud)

地址字段是映射所占用的过程中的地址空间。

perms字段是一组权限:

 r = read
 w = write
 x = execute
 s = shared
 p = private (copy on write)
Run Code Online (Sandbox Code Playgroud)

offset字段是文件/其他文件的偏移量;

dev是设备(主要:次要);

inode是该设备上的inode。0表示没有inode与内存区域关联,就像BSS(未初始化的数据)一样。

路径名字段通常将是支持映射的文件。对于ELF文件,您可以通过查看ELF程序标头(readelf -l)中的Offset字段轻松地与offset字段进行协调。

在Linux 2.0下,没有提供路径名的字段。