在现代操作系统中,内存可用作抽象资源。进程暴露给虚拟地址空间(独立于所有其他进程的地址空间),并且存在用于将任何虚拟地址映射到某个实际物理地址的整个机制。 我怀疑是:
如果每个进程都有自己的地址空间,那么它应该可以自由访问同一个地址。因此,除了.data,.bss,.text等权限限制部分之外,还应该可以随意更改任何地址的值。但这通常会给出分段错误,为什么呢?
为了获取动态内存,我们需要做一个malloc。如果整个虚拟空间可供进程使用,那为什么不能直接访问它呢?
程序的不同运行会导致变量的不同地址(堆栈和堆上)。为什么这样,每次运行的环境是一样的?它是否不影响可用的可寻址内存量? (它与地址空间随机化有关吗?)
内存分配的一些链接(例如在堆中)。
在不同地方提供的数据非常混乱,因为它们谈论的是旧时代和现代时期,往往无法区分它们。 Linux说,如果有人能够在保持现代系统的同时澄清疑虑,那将会很有帮助。
感谢。
答案 0 :(得分:5)
从技术上讲,操作系统能够在访问时分配任何内存页面,但重要的原因是它不应该或不能:
不同的记忆区域有不同的用途。
操作系统可能会假设所有无法识别的内存访问都是尝试分配更多堆空间,但是:
1<<31
(最高位设置)或高于3<<30
(最高两位设置)的内存都是内核内存。您不应该假设用户空间中存在任何未分配的内存区域。0x12341234
;应用程序:但我希望存储我的数据 )。您可以通过触摸数组的末尾来告诉操作系统(无论如何这都是不可靠的),但是更容易调用操作系统功能。函数调用“给我10MB的堆”是个好主意,而不是“从0x12345678
开始给我10MB的堆”程序的不同运行会导致变量的不同地址
这称为内存布局随机化,除了适当的权限(堆栈空间不可执行)之外,还可以使缓冲区溢出攻击更加困难。你仍然可以杀死应用程序,但不能执行任意代码。
内存分配的一些链接(例如在堆中)。
你的意思是,分配器使用什么算法?最简单的算法是始终在最快的可用位置进行分配,并从每个内存块链接到下一个内存块,如果它是空闲块或已用块,则存储该标志。更高级的算法总是以2的幂或一些固定大小的倍数来分配块,以防止内存碎片(大量小的空闲块)或链接不同结构的块以更快地找到足够大小的空闲块。
更简单的方法是永远不要取消分配并只指向第一个(也是唯一的)空闲块并保持其大小。如果剩余空间太小,请将其丢弃并向操作系统索取新的空间。
内存分配器没什么神奇之处。他们所做的就是: *向操作系统询问大区域和 *将其分区为较小的块 *没有 *浪费太多空间或 *花了太长时间。
无论如何,关于内存分配的维基百科文章是http://en.wikipedia.org/wiki/Memory_management。
一种有趣的算法称为"(binary) buddy blocks"。它拥有几个二次幂大小的池,并将它们递归地分成更小的区域。然后,每个区域都可以完全分配,完全免费或分成两个区域(伙伴),这两个区域并非完全免费。如果它被拆分,那么一个字节就足以保持该块中最大空闲块的大小。