【发布时间】:2015-05-02 20:07:09
【问题描述】:
当一个 C 程序启动时,它如何要求操作系统为静态变量提供足够的内存空间? 并且在运行时如何向操作系统内存空间请求自动变量?
我也想知道它在执行后是如何释放这些内存空间的。
请尽量做到最准确。如果操作系统的解释有所不同,请优先考虑类似 UNIX 的操作系统。
【问题讨论】:
标签: c memory memory-management operating-system allocation
当一个 C 程序启动时,它如何要求操作系统为静态变量提供足够的内存空间? 并且在运行时如何向操作系统内存空间请求自动变量?
我也想知道它在执行后是如何释放这些内存空间的。
请尽量做到最准确。如果操作系统的解释有所不同,请优先考虑类似 UNIX 的操作系统。
【问题讨论】:
标签: c memory memory-management operating-system allocation
全局变量和具有静态生命周期的变量通常存储在由操作系统的可执行加载器设置的数据段中。
这个加载器可能会,正如@John Zwinck 在 Unix 上所说的那样。例如在 Windows 上有 VirtualAlloc,它也可以用于在另一个程序的地址空间中分配内存。
局部变量通常存储在所谓的堆栈中。堆栈上的分配非常快,因为它们通常只包含对堆栈指针寄存器(x86 处理器系列上的 sp、esp、rsp)的修改。因此,当您有一个 int (大小:4 字节)时,该寄存器将随着堆栈向下增长而简单地减少 4。在作用域结束时,堆栈寄存器的旧状态被恢复。
这也使得堆栈溢出很危险,因为您可以覆盖堆栈上不应修改的其他变量,例如函数调用的返回地址。
动态变量是使用 malloc (C) 或 new (C++) 或任何操作系统特定分配函数分配的变量。这些被放置在所谓的堆上。它们一直存在,直到使用 free/delete/os-specific-deallocator 清理它们或程序退出(在这种情况下,一个健全的操作系统负责清理)。
动态分配也是三者中最慢的,因为它需要调用操作系统。
【讨论】:
类 Unix 系统上的内存分配是通过使用 sbrk() 和 mmap() API 调用操作系统来完成的。
sbrk() 用于扩大“数据段”,它是(虚拟)地址的连续范围。 mmap() 在许多现代系统中用作对此的一种补充,因为它可以分配块,以后可以独立释放(这意味着不会像 sbrk() 那样留下“漏洞”)。
在 C 语言中,malloc() 作为面向用户的 API 用于内存分配。你可以在这里阅读更多关于它如何映射到我之前提到的低级函数的信息:How are malloc and free implemented?
【讨论】:
静态变量位于代码后面的 BSS 段中。自动变量位于进程虚拟内存末尾的堆栈上。两者都是在编译时定义的。然后在程序启动时创建内存布局。 brk()、sbrk() 和 mmap() 可以在运行时操作虚拟内存(尤其是堆)(例如使用 malloc()/free()),但这些函数与静态和自动变量无关!
【讨论】: