Abh*_*osh 3 c malloc memory-management heap-memory sbrk
自从我被介绍到 以来C,我就被告知C动态内存分配是使用家族中的函数完成的malloc。我还了解到,动态分配的内存malloc是在进程的堆部分分配的。
各种操作系统教科书都说这malloc涉及系统调用(虽然并不总是但有时)来将堆上的结构分配给进程。现在假设malloc返回指向堆上分配的字节块的指针,为什么它需要系统调用。函数的激活记录放置在进程的堆栈部分中,并且由于“堆栈部分”已经是进程虚拟地址空间的一部分,所以激活记录的压入和弹出、堆栈指针的操作,只需从虚拟地址空间的最高可能地址。它甚至不需要系统调用。
现在基于同样的理由,由于“堆部分”也是进程虚拟地址空间的一部分,为什么需要系统调用来在该部分中分配字节块。像这样的例程malloc可以自行处理“空闲”列表和“已分配”列表。它需要知道的只是“数据部分”的结尾。某些文本说系统调用对于“将内存附加到进程以进行动态内存分配”是必要的,但是如果malloc在“堆部分”上分配内存,为什么需要在 期间将内存附加到进程malloc?可以简单地取自过程中已经一部分的部分。
在阅读 Kernighan 和 Ritchie 的《C 编程语言》[2e] 文本时,我发现了他们对该malloc函数的实现 [第 8.7 节第 185-189 页]。作者说:
malloc根据需要调用操作系统获取更多内存。
这就是操作系统文本所说的,但与我上面的想法相反(如果malloc在堆上分配空间)。
由于向系统请求内存是一项相对昂贵的操作,因此作者不会在每次调用 时都这样做,因此他们创建了一个至少请求单位的malloc函数;这个较大的块根据需要被切碎。而基本的空闲列表管理是由.morecoreNALLOCfree
但问题是作者使用sbrk()向操作系统请求内存morecore。现在维基百科说:
brk和是 Unix 和类 Unix 操作系统中使用的基本内存管理系统调用,用于控制分配给进程数据段sbrk的内存量。
在哪里
数据段(通常表示为.data)是目标文件或程序的相应地址空间的一部分,其中包含初始化的静态变量,即全局变量和静态局部变量。
我猜这不是“堆部分”。[数据部分是上图中从下数第二部分,而堆是从下数第三部分。]
我完全困惑了。我想知道到底发生了什么以及这两个概念如何正确?请通过将分散的碎片连接在一起来帮助我理解这个概念......
在您的图表中,标记为“数据”的部分更准确地称为“静态数据”;当进程启动时,编译器会为所有全局变量预先分配该内存。
使用的堆malloc()是进程数据段的其余部分。最初在进程中分配给它的内存非常少。如果malloc()需要更多内存,可以用来sbrk()扩展数据段的大小,或者可以用来mmap()在地址空间的其他位置创建额外的内存段。
为什么malloc()需要这样做?为什么不简单地让整个地址空间可供它使用呢?这有历史和现实的原因。
历史原因是早期的计算机没有虚拟内存。当在进程之间切换时,分配给进程的所有内存都会批量交换到磁盘。因此,仅分配实际需要的内存页非常重要。
实际原因是这对于检测各种错误很有用。如果您因取消引用未初始化的指针而遇到分段冲突错误,那么您已经从中受益。进程的大部分虚拟地址空间未分配给该进程,这使得未初始化的指针可能指向不可用的内存,并且在尝试使用它时会出现错误。
堆(向上增长)和堆栈(向下增长)之间还存在未分配的间隙。这用于检测堆栈溢出——当堆栈尝试使用该间隙中的内存时,它会收到一个错误,该错误会转换为堆栈溢出信号。
| 归档时间: |
|
| 查看次数: |
4332 次 |
| 最近记录: |