【问题标题】:When is memory allocated and de-allocated static and dynamic memory in C?在 C 中何时分配和取消分配静态和动态内存?
【发布时间】:2020-01-10 07:50:03
【问题描述】:

我现在正在学习 C,并试图弄清楚 C 的内存管理是如何工作的。如果我错了,请纠正我,但据我所知:

静态内存分配 - 这发生在编译期间。编译器分配静态内存所需的必要内存。

静态内存释放 - 当块/函数完成运行(对于局部变量)或整个程序完成执行(对于全局变量)时,内存会自动释放。

动态内存分配 - 内存是在运行时分配的,因为此时输入的大小是未知的。

动态内存释放 - 内存在 free() 执行时被释放。

这是对的吗?我错过了什么吗?

【问题讨论】:

标签: c memory memory-management


【解决方案1】:

C 语言中有 3 种不同的存储时长:

  • 静态:变量的生命周期就是程序的生命周期。它在加载时分配(仅在编译时定义)并且仅在操作系统卸载程序时释放。静态变量是在任何函数之外声明的变量,以及具有 static 修饰符的局部变量(在函数或块中声明)
  • 自动:自动变量在块(或函数)内声明,没有存储修饰符。它们的生命周期始于集团之初,终止于集团之末。它们通常在 bloc 的开头分配并在其结尾释放,但由于 as if 规则,优化编译器可以更快地分配它们并稍后释放它们,例如如果 bloc 位于循环内。
  • 动态:它们是通过malloc手动分配的,只会被free释放

常见的实现为自动变量使用系统堆栈,为动态变量使用内存池(在需要更多内存时询问操作系统),但这是一个实现细节

使用多线程时,还有第四种存储时长:线程存储时长。这些变量使用_Thread_local 存储类修饰符声明。它们的生命周期就是线程的持续时间,每个线程都有自己的副本。

对于常见的实现,它们的管理方式与静态变量相同:它们在线程创建时由操作系统分配,并在线程结束时回收(仍然由操作系统)。


关于你的措辞的一些评论:

静态内存分配 - 这发生在编译期间。

请注意,编译时间和加载时间是不同的。在构建时只创建一个文件,内存只由系统在运行时分配

静态内存释放 - 当块/函数完成运行时自动释放内存(对于局部变量)...

范围(本地与全局)和存储持续时间之间存在混淆。一个函数可以包含静态变量,这就是static关键字的原因之一

动态内存分配——内存是在运行时分配的因为此时输入的大小是未知的

这是程序员使用动态内存的一个可能原因,但也可能有其他原因,例如因为这样代码会更干净。特别是当你想用 C 语言模仿面向对象编程时,动态内存是一个很好的工具。

【讨论】:

  • VLAs 是动态的还是静态的?
  • @TruthSeeker 标准没有定义它们的分配方式,但很可能它们是自动的并在堆栈上分配。我从未见过做其他任何事情的实现。
  • @TruthSeeker。它们按定义是自动变量,因为对于数组如果将标识符声明为具有静态或线程存储持续时间的对象,则它不应具有可变长度数组类型。 (6.7.6.2 数组声明符§2)。而且malloc不能声明VLA。
【解决方案2】:

我认为你说的大部分话都是正确的。我想补充几点。

对于全局和静态变量,如果它们被初始化,它们的值会出现在生成的二进制文件中,所以是的,静态内存分配(实际上它不是内存,但无论如何)发生在编译时,但考虑未初始化的全局变量(bss 部分) .只有它们的长度被写入生成的二进制图像中,因为将数千个零写入编译后的图像会很愚蠢。在这种情况下,内存分配由加载程序在加载时处理。它分配所需的空间,将它们映射到变量的虚拟地址并将内存清零。

而free并不一定意味着你将未使用的内存交给操作系统。通常,c 标准库会跟踪已释放的块,并在可能的情况下将它们连接起来,以便下次您想要 malloc 时不执行 sbrk 或等效系统调用,因为它们相对昂贵。我相信高度依赖于库的实现

【讨论】:

    猜你喜欢
    • 2012-01-13
    • 2014-10-12
    • 2015-02-27
    • 2016-02-03
    • 2014-10-03
    • 1970-01-01
    • 2015-07-23
    • 2016-10-21
    相关资源
    最近更新 更多