C函数内存分配

时间:2012-07-10 04:23:33

标签: c memory memory-management

在C中,分配函数的时间和内存中的位置是什么时候?

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

3 个答案:

答案 0 :(得分:2)

在将函数加载到内存时,始终从代码段分配C函数的内存。如果函数属于动态链接库,则程序可以在任意时间加载和卸载它。

答案 1 :(得分:1)

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

我选择失败,试图将其压缩成4种类型。

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

代码存储应该非常简单,所以我只会稍微复杂一点:将一组思想翻译成一个过程语言片段,从此称为“函数”,被翻译成一系列机器指令。

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

(让我们不要进入in-linning)


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

常量可能会也可能不会获得自己的ROM存储区域...其编译器/优化特定。


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

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

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

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

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


动态内存通常由malloc和free管理:通过指针访问的增长地址堆栈的内存块的守护者。这形成了一个错误命名的Heap区域(因为你最有可能得到一个瑞士的cheesse,而不是一堆)。

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

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

Dyn-memory区域通常夹在全局和Stack之间...有些嵌入式编译器会让你指定两者的大小。

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

答案 2 :(得分:0)

内联函数...

伟大的解释......

我想提供有关未涵盖的内联函数的内存分配的详细信息。内联函数可以被认为是一个宏,其中函数的调用被代码替换,并且还进行参数评估。 在函数之前给出关键字内联不需要使它成为内联函数,它只是建议编译器这是内联的候选者。编译器最终选择是否可以是内联函数。因此,内存分配类似于函数。