编译器是否为最大的代码块或C中的所有块保留内存?

时间:2019-02-05 07:24:15

标签: c memory memory-management

C编译器是否在运行程序之前分配了所有必需的内存,还是为最大的内存块分配了内存? 在这两种情况下,我都在询问静态分配的内存,我了解动态内存分配是在运行时请求内存。

请参见下面的代码

    #include <stdio.h>

    int global_flag = 1; //using 4 bytes

    void create_8_bytes()
    {
        /*
         * create 2 integers , total 8 bytes
        */
        int a = 3;
        int b = 6;

    }


    void create_4_bytes()
    {
        /*
         * 1 variable , total 4 bytes
        */
        int a  = 1;
    }

    void main()
    {
        create_8_bytes(); //8 bytes
        create_4_bytes(); //4 bytes
        puts("done");
    }

运行上述程序需要多少内存?

2 个答案:

答案 0 :(得分:4)

在非平凡的C / C ++程序中,通常无法预先知道运行时需要多少内存。这意味着,即使您的编译器尽了最大的努力,也无法始终生成静态地仅保留适当数量的内存的程序。

现代平台通常在某种程度上区分三种“类型”的内存:

  1. 程序在整个持续时间内分配和使用的内存(静态/全局变量,函数等)
  2. 程序可以使用malloc等在运行时请求的内存
  3. 堆栈内存

您的程序所需的静态内存量无法轻松估算,因为它取决于操作系统,编译器,标准库等,因此变化很大。但是,您的程序非常小,因此可以令人惊讶的是,如果在任何平台上都需要超过几千字节的数据。在内存特别宝贵的平台上,可能只有几个字节。

您的程序不使用malloc或其他分配函数,因此它不需要此类内存。

堆栈存储器是魔术发生的地方。堆栈是调用函数时程序可以使用(和重复使用)的内存区域。它的大小取决于平台(通常记录在某处),并且操作系统通常会优化其使用,以使程序在实际尝试使用内存之前不将其提供给程序。

如果堆栈内存不足,则会发生未定义的行为。在内存很宝贵的平台上,您可能会破坏程序的其他部分。如今,在大多数现代平台上,您都会崩溃。

假设您的程序没有经过优化,并且掩盖了一些平台细节,那么内存使用将看起来像这样:

  • 程序开始
    • 您不使用堆栈内存
  • 输入main:设置堆栈帧(约16个字节的整理信息)
    • 您使用16字节的堆栈内存
  • 输入create_8_bytes:设置堆栈帧(约16个字节的内务处理,8个字节的变量)
    • 您使用40字节的堆栈内存
  • 离开create_8_bytes:释放create_8_bytes使用的堆栈框架
    • 您使用16个字节的内存
  • 输入create_4_bytes:设置堆栈帧(约16个字节的内务处理,4个字节的变量)
    • 您使用36个字节的内存
  • 离开create_4_bytes:释放堆栈框架
    • 您使用16个字节的内存
  • 输入puts(使用未知的内存量)
    • 您使用16 + ???内存字节
  • 离开puts
    • 您使用16字节的堆栈内存
  • 离开main
    • 您不使用堆栈内存

如您所见,您使用的内存量随着输入和离开函数的增加而缩小。

尽管这为如何使用堆栈内存提供了正确的直觉,但请记住,如果编译器可以证明不会改变结果,则通常可以删除程序的某些部分。这意味着如果您不使用局部变量,您可能会希望它们消失,即使您确实使用了局部变量,编译器也可能会使用其他转换,从而使这些变量完全不使用堆栈内存。编译器还可能将堆栈内存用于您未明确告知它的事情。

答案 1 :(得分:2)

取决于编译器,您的环境,操作系统以及其他因素。无论如何,总会有一个开销要大于几个字节。

此外,该程序的大部分可能已被优化,因此那些ints可能无关紧要。该程序只能简化为puts("done");

那些ints将在堆栈中。因此create_8_bytes将导致创建一个新的堆栈框架,该堆栈框架具有两个int的空间(还有更多空间,例如堆栈指针,因此,数字将关闭)。然后,完成create_8_bytes后,其堆栈帧将无效,然后调用create_4_bytes,这将使堆栈帧保存该int。当然,所有情况都假定没有内联或优化的内容。

您可能想知道,a中的bcreate_8_bytesa中的create_4_bytes是否会同时存在。他们不会。当然,实际的内存消耗并不代表函数调用的开销,程序本身(包括在puts后面加载必要的代码)以及操作系统如何处理内存分配的总和会更多。与那十二个字节有关。而且,如果您要编译调试版本,那么所有这些都将再次大不相同,因为编译器不会优化原本会优化的东西,而会在程序中包含原本不会的东西,甚至可能提供了一个沙盒环境来运行您的程序,即使是最简单的应用程序也要占用数兆字节。