C函数内存分配

2023-12-08

在 C 语言中,函数何时分配以及它在内存中的何处?

函数的内存是在第一次编译程序时分配的,还是在第一次看到函数调用时分配的?它是分配在堆栈上还是在代码段中?


你的问题问得很好,但是要做好应对一些额外复杂性的准备,因为其中一些东西会接触到运行代码的 CPU 中的裸露晶体管......

我选择将其压缩为 4 种类型,但惨遭失败。

  • 全局存储
  • 代码存储
  • 本地存储
  • 动态存储

代码存储应该非常简单,所以我只是将其复杂化一点:将一系列思想转化为过程语言片段(此后称为“函数”),然后将其转化为一系列机器指令。

这些需要由处理器获取并执行,因此它必须位于 ROM 或 RAM 中......定义代码存储区域。即使该函数被多次调用甚至递归调用,其代码也只有一个实例。

(我们不要进入内联)


全局数据存储是 RAM,所有不在函数中声明的变量都可以在其中生存(每个声明只有一个实例),加上声明为静态的变量(在函数内或函数外)。这些由绝对(或准)地址引用。

常量可能有也可能没有自己的 ROM 存储区域……其编译器/优化特定。


函数的本地存储是用于参数/返回传递和局部变量的包(在其中声明,因此仅对其可见),并且对函数的每次调用都需要一个单独的包,以便每次调用都获得其单独的上下文。

通常(也有令人难忘的例外)我们使用Call-Stack机制来堆积每个函数调用生成的几个本地存储区域。它越来越不确定,但你会发现这是一个以递减内存地址增长的堆栈帧。

因此,本地存储是编译器函数调用代码(自动为您完成)放置函数参数、被调用函数的返回占位符、调用函数的返回地址以及所有非静态(并优化为内部寄存器使用)变量。每个呼叫一个。引用这些局部变量和参数的函数代码将...错误..通过堆栈指针加上偏移量(指向当前堆栈帧结束地址的CPU寄存器)来引用后者(函数代码怎么可能否则知道内存地址吗?)。

调用函数涉及设置其本地存储,最终将参数复制到其中(推入堆栈)并初始化一些本地变量,然后跳转到函数代码。返回是将被调用函数的返回值复制到调用函数的本地存储中,销毁被调用的F本地存储,将堆栈指针放在之前堆积的本地存储袋的末尾,并跳转到保存的调用者下一条指令地址(弹出东西)。全做完了。

查看单个 C 进程的内存快照,您可以看到一个具有多个底部堆积的本地存储区域的堆栈,这些区域将按照特定程序执行的函数调用/返回模式阻止增长和收缩。


动态内存通常由 malloc 和 free 管理:它们是通过指针访问的不断增长的地址堆栈的内存块的守护者。这形成了一个错误命名的堆区域(因为随着时间的推移,您很可能会得到瑞士奶酪,而不是堆)。

这些内存块可用于任何目的,挑战是确保不要忘记释放它们,否则及时您将“泄漏”到调用堆栈中(很容易看出这将是多么具有破坏性)。

使用由 malloc/free 管理的动态内存需要一些额外的规则,但对于避免巨大的本地或浪费的全局存储非常有用(在函数需要处理一堆数据并且可以被调用几次的情况下,或者很少需要存储在内存中的一大块数据)。

动态内存区域通常夹在全局和堆栈之间...一些嵌入式编译器将允许您指定两者的大小。

Malloc 和 free 并不是管理动态内存的唯一方法,我目前正在使用一个自制的反向引用分配器,它不需要 free()。无纪律的代码,没有泄漏......耶!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C函数内存分配 的相关文章

随机推荐