分段线性插值c语言程序_程序的内存布局(下)

60630f4348adaafdae4c9a6fe6efb604.png
声明:原出处为: https:// manybutfinite.com/post/ anatomy-of-a-program-in-memory/
翻译:RobotCode俱乐部

在堆栈下面,我们有内存映射段。在这里,内核直接将文件的内容映射到内存。任何应用程序都可以通过Linux mmap()系统调用请求这样的映射。内存映射是执行文件I/O的一种方便高效的方法,因此常用于加载动态库。还可以创建不对应于任何文件的匿名内存映射,用于程序数据。在Linux中,如果您通过malloc()请求一个大内存块,C库将创建这样一个匿名映射,而不是使用堆内存。'大内存'表示大于MMAP_THRESHOLD字节,默认大小为128kb,可通过mallopt()进行调整。

堆提供运行时内存分配,就像栈一样,这意味着数据必须比执行分配的函数活得更久,这与栈不同。大多数语言都提供了堆管理。在C语言中,堆分配的接口是malloc()。(以后会讨论为什么有时malloc不是在堆上分配内存)

如果堆中有足够的空间来满足内存请求,那么程序运行时可以在不涉及内核的情况下处理它。否则,通过brk()系统调用(实现)来扩大堆,为请求的块腾出空间。

堆管理是复杂的,需要复杂的算法来实现高效的内存使用。堆请求所需的时间可以有很大的不同。实时系统有专门的分配器来处理这个问题。堆也会变得支离破碎,如下所示:

676c55067608915d4b8f227d9b16abb0.png

最后,我们讨论内存的最低段:BSS、数据段和程序段(程序段有时也翻译成文本段)。BSS和数据段都为c中的静态(全局)变量存储内容。区别在于BSS存储未初始化的静态变量的内容,这些静态变量的值在源代码中没有被初始化设置。BSS内存区域是匿名的:它不映射任何文件。如果定义了 static int cntActiveUsers,那么cntActiveUsers的内容就存在于BSS中。

另一方面,数据段保存源代码中初始化的静态变量的内容。这个内存区域不是匿名的。它映射程序二进制映像中包含源代码中给定的初始静态值的部分。因此,如果定义了 static int cntWorkerBees = 10,则cntWorkerBees的内容位于数据段中,内容为10。即使数据段映射一个文件,它也是一个私有内存映射,这意味着对内存的更新不会反映在底层文件中。必须是这样,否则分配给全局变量将改变磁盘上的二进制映像。不可思议!

图中的示例比较复杂,因为它使用指针。在这种情况下,指针gonzo的内容驻留在数据段中。但是,它所指向的实际字符串不是。该字符串位于程序段(文本段)中,该文本段是只读的,存储所有代码,也包括字符串常量。文本段还映射内存中的二进制文件,但写入该区域会导致程序出现段错误(因为是只读的)。下面的图表显示了这些内存分段和我们的示例变量:

474dc72c561759f5249c8651663c5771.png

可以通过读取文件/proc/pid_of_process/maps来检查Linux进程中的内存区域。请记住,一个段可能包含许多区域。例如,每个内存映射文件在mmap段中通常有自己的区域,动态库有类似于BSS和数据的额外区域。下一篇文章将阐明“区域”的真正含义。另外,有时人们说“数据段”是指所有的数据+ bss +堆。

可以使用nm和objdump命令检查二进制镜像,以显示符号、它们的地址、段等等。最后,上面描述的虚拟地址布局是Linux中的“灵活”布局方式,这是几年来的默认布局。它假设我们有一个RLIMIT_STACK的值。如果不是这样,Linux就会恢复到“经典”布局,如下所示:

65f11077b59c04f5bc9419223fd4baad.png

以上是关于虚拟地址的空间布局。下一篇文章将讨论内核如何跟踪这些内存区域,然后我们来看看内存映射,文件读写是如何与这些联系在一起的,以及内存使用数据意味着什么。

--END

由于本人水平有限,翻译必然有很多不妥的地方,欢迎指正。同时,欢迎关注下方微信公众号,一起交流学习:)

23ad5a779493c6b31679856333fa23e3.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值