【问题标题】:Memory layout of C program (stack and heap)C程序的内存布局(栈和堆)
【发布时间】:2020-04-21 04:00:50
【问题描述】:

堆栈和堆在系统中是通用的,还是专门为每个创建的进程创建的?

【问题讨论】:

  • 每个进程都有自己的私有栈和堆。
  • 更具体地说,Linux 中的每个进程都有自己的私有内存映射。这就是为什么一个进程中的指针通常不能与另一个进程共享,即使两者都运行完全相同的程序。
  • 一个进程甚至可以同时拥有多个调用栈(参见makecontext(3)sigaltstack(2)、线程等)

标签: c linux linux-kernel embedded-linux


【解决方案1】:

简短回答是的,每个进程都有自己的堆栈(必须是 这种情况,因为每个正在运行的实体都必须有一个)和堆。

长答案:继续阅读。

地址空间

每个进程都拥有一个地址空间,其中一部分是堆栈和 堆。代码和全局数据(只读和读写)也是 包含在该地址空间中。

当我说一个进程拥有一个地址空间时,这意味着一个 进程不能窥视另一个进程的地址空间。这 内存保护是在硬件中完成的,使用一种叫做 内存管理单元 (MMU),通常是 CPU 的一部分。一 可以说地址空间是硬件的抽象 实现细节称为 MMU。

所说的抽象——地址空间——赋予每个进程感知 它有一个可用的线性字节数组,编号从 0 到 2^64-1(在 64 位系统上)。现代系统很少配备 有这么大的内存,所以通常只有该地址的一部分 空间由物理内存支持。

每当一个进程访问在其内部无效的内存时 地址空间,它被终止:它崩溃了。一个抽象的 崩溃(人们喜欢抽象的软件)正在接收信号 - SIGSEGV(“分段违规”)在无效内存的情况下 访问。

/proc 文件系统

一种称为proc 的特殊文件系统通常安装在 /proc。为了演示地址空间及其布局,我开始了一个 任意程序,

$ sleep 10000&
[1] 12010

在后台启动它 (&) 会给我进程 ID,我 用于 cd 进入/proc 中的进程目录,

$ cd /proc/12010

请注意,/proc 不是磁盘上的目录,而是某个 有一个有趣的名称(进程 ID),看起来像一个目录,是一个 目录,并具有呈现给用户的文件和子目录 进程的属性。在这里,我们感兴趣的是 地址空间的内存布局 - 地址中的有效区域 空间。

这是 `/proc/PID/maps 文件显示的内容,

$ cat maps 
55b782825000-55b782827000 r--p 00000000 fd:00 1180965                    /usr/bin/sleep
55b782827000-55b78282b000 r-xp 00002000 fd:00 1180965                    /usr/bin/sleep
55b78282b000-55b78282d000 r--p 00006000 fd:00 1180965                    /usr/bin/sleep
55b78282e000-55b78282f000 r--p 00008000 fd:00 1180965                    /usr/bin/sleep
55b78282f000-55b782830000 rw-p 00009000 fd:00 1180965                    /usr/bin/sleep
55b783115000-55b783136000 rw-p 00000000 00:00 0                          [heap]
7ff262d19000-7ff26fcfe000 r--p 00000000 fd:00 1188440                    /usr/lib/locale/locale-archive
7ff26fcfe000-7ff26fd23000 r--p 00000000 fd:00 1183177                    /usr/lib64/libc-2.30.so
7ff26fd23000-7ff26fe72000 r-xp 00025000 fd:00 1183177                    /usr/lib64/libc-2.30.so
7ff26fe72000-7ff26febc000 r--p 00174000 fd:00 1183177                    /usr/lib64/libc-2.30.so
7ff26febc000-7ff26febd000 ---p 001be000 fd:00 1183177                    /usr/lib64/libc-2.30.so
7ff26febd000-7ff26fec0000 r--p 001be000 fd:00 1183177                    /usr/lib64/libc-2.30.so
7ff26fec0000-7ff26fec3000 rw-p 001c1000 fd:00 1183177                    /usr/lib64/libc-2.30.so
7ff26fec3000-7ff26fec9000 rw-p 00000000 00:00 0 
7ff26feeb000-7ff26feed000 r--p 00000000 fd:00 1180257                    /usr/lib64/ld-2.30.so
7ff26feed000-7ff26ff0d000 r-xp 00002000 fd:00 1180257                    /usr/lib64/ld-2.30.so
7ff26ff0d000-7ff26ff15000 r--p 00022000 fd:00 1180257                    /usr/lib64/ld-2.30.so
7ff26ff16000-7ff26ff17000 r--p 0002a000 fd:00 1180257                    /usr/lib64/ld-2.30.so
7ff26ff17000-7ff26ff18000 rw-p 0002b000 fd:00 1180257                    /usr/lib64/ld-2.30.so
7ff26ff18000-7ff26ff19000 rw-p 00000000 00:00 0 
7ffffb0e8000-7ffffb10a000 rw-p 00000000 00:00 0                          [stack]
7ffffb1eb000-7ffffb1ee000 r--p 00000000 00:00 0                          [vvar]
7ffffb1ee000-7ffffb1ef000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

以这一行为例

55b78282f000-55b782830000 rw-p 00009000 fd:00 1180965                    /usr/bin/sleep

是进程中r读取-w可读取的全局数据的映射, 从 /usr/bin/sleep 填充(在文件中的偏移量不是 此处显示)。

另一个映射,

55b782827000-55b78282b000 r-xp 00002000 fd:00 1180965                    /usr/bin/sleep

r可读且executable - 代码,由 相同的二进制文件。文件中的其他行显示取自的映射 包含类似工件的共享库。

最后有两个映射stackheap不是 从文件中填充,而是由 进程创建时的内核。

【讨论】:

    猜你喜欢
    • 2014-12-05
    • 2016-06-23
    • 1970-01-01
    • 2017-09-24
    • 1970-01-01
    • 2014-05-13
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多