【问题标题】:Difference between static memory allocation and dynamic memory allocation静态内存分配和动态内存分配的区别
【发布时间】:2012-01-13 04:39:10
【问题描述】:

我想知道静态内存分配和动态内存分配有什么区别?

你能举个例子解释一下吗?

【问题讨论】:

    标签: c memory memory-management dynamic-memory-allocation static-memory-allocation


    【解决方案1】:

    这是一个标准的面试问题:

    动态内存分配

    内存是在运行时使用calloc()malloc() 和朋友分配的。它有时也被称为“堆”内存,尽管它与堆数据结构ref 无关。

    int * a = malloc(sizeof(int));
    

    在调用free() 之前,堆内存是持久的。换句话说,您可以控制变量的生命周期。

    自动内存分配

    这就是通常所说的“栈”内存,当你进入一个新的作用域时分配(通常是当一个新函数被压入调用栈时)。一旦你移出范围,自动内存地址的值是未定义的,它是一个error to access them

    int a = 43;
    

    请注意,范围并不一定意味着功能。作用域可以嵌套在一个函数中,并且该变量将只在它被声明的块内的作用域内。另请注意,未指定分配此内存的位置。 (在 sane 系统上,它将在堆栈上,或注册以进行优化)

    静态内存分配

    在编译时分配*,变量在静态内存中的生命周期是lifetime of the program

    在 C 中,可以使用 static 关键字分配静态内存。范围只是编译单元。

    事情变得更有趣了when the extern keyword is considered。当extern 变量被定义时,编译器会为其分配内存。当extern 变量被声明 时,编译器要求该变量在别处定义。未声明/定义extern变量将导致链接问题,而未声明/定义static变量将导致编译问题。

    在文件范围内,静态关键字是可选的(在函数之外):

    int a = 32;
    

    但不在函数范围内(函数内部):

    static int a = 32;
    

    从技术上讲,externstatic 是 C 中两个独立的变量类别。

    extern int a; /* Declaration */
    int a; /* Definition */
    

    *静态内存分配注意事项

    说静态内存是在编译时分配的,这有点令人困惑,特别是如果我们开始考虑编译机和主机可能不同,甚至可能不在同一个架构上。

    最好认为静态内存的分配由编译器处理而不是在编译时分配

    例如,编译器可能会在编译后的二进制文件中创建一个大的data 段,当程序加载到内存中时,程序的data 段内的地址将用作分配内存的位置。如果使用大量静态内存,这具有使编译的二进制文件非常大的明显缺点。可以编写从不到六行代码生成的数 GB 二进制文件。另一种选择是让编译器注入初始化代码,该代码将在程序执行之前以其他方式分配内存。此代码将根据目标平台和操作系统而有所不同。在实践中,现代编译器使用启发式方法来决定使用哪些选项。您可以自己尝试通过编写一个小型 C 程序来分配一个包含 10k、1m、10m、100m、1G 或 10G 项的大型静态数组。对于许多编译器来说,二进制大小会随着数组的大小线性增长,超过某个点,随着编译器使用另一种分配策略,它会再次缩小。

    注册内存

    最后一个内存类是“寄存器”变量。正如预期的那样,寄存器变量应该分配在 CPU 的寄存器上,但实际上由编译器决定。您不能使用 address-of 将寄存器变量转换为引用。

    register int meaning = 42;
    printf("%p\n",&meaning); /* this is wrong and will fail at compile time. */
    

    大多数现代编译器在选择哪些变量应该放入寄存器方面比你聪明:)

    参考资料:

    【讨论】:

    • 注意:我建议改为int * a = malloc(sizeof(*a));,以避免重复a 的类型。如果 a 的类型发生变化,这会使事情变得更容易。
    • 其实叫heap,跟heap数据结构没有关系。在这种情况下,堆意味着一个凌乱的地方
    • "静态内存分配...在编译时分配" 你的意思是分配大小是在编译时确定的吗?内存分配不是只在运行时发生吗?
    • 嘿,我有一个疑问,如果您仍然响应:(。自动内存分配呢?编译器是否还会将这些局部变量的地址存储在数据部分并将其传递给可执行文件。当代码执行(并进入作用域)这些地址实际上将用作分配内存的位置。或者它实际上只在运行时分配,没有任何地址生成和我的编译器处理?
    • @LocalHost 自动变量的作用域是定义它们的上下文(大括号)的生命周期。通常在运行时在调用堆栈上分配。它绝对存储在数据部分。您可以在此处阅读 C18 标准:(6.2.4.5-7)web.archive.org/web/20181230041359/http://www.open-std.org/jtc1/…
    【解决方案2】:

    静态内存分配:

    • 变量被永久分配
    • 分配是在程序执行之前完成的
    • 它使用名为stack的数据结构来实现静态分配
    • 效率较低
    • 没有没有内存可重用性

    动态内存分配:

    • 在程序单元激活时才分配变量
    • 分配完成程序执行期间
    • 它使用名为heap的数据结构来实现动态分配
    • 更高效
    • 存在内存可重用性。不需要时可以释放内存

    【讨论】:

    • “静态内存分配 [...] 它使用称为堆栈的数据结构来实现静态分配” ,这是不正确且具有误导性的。请参阅我的帖子了解自动分配和静态分配之间的区别。静态内存可能使用堆栈。这强烈依赖于实现,并且可以为同一实现使用多种策略。我也不确定您所说的“效率较低”是什么意思。 @Trieu Toan,您用错误的编辑改变了这个答案的含义。
    【解决方案3】:

    有三种类型的分配——静态、自动和动态。

    静态分配意味着,在程序启动时为变量分配内存。创建程序时,大小是固定的。它适用于全局变量、文件范围变量以及在函数内部定义的以static 限定的变量。

    自动内存分配发生在函数内部定义的(非静态)变量上,通常存储在堆栈中(尽管 C 标准不强制要求堆栈被使用)。您不必使用它们保留额外的内存,但另一方面,也可以有限地控制此内存的生命周期。例如:函数中的自动变量只存在于函数完成之前。

    void func() {
        int i; /* `i` only exists during `func` */
    }
    

    动态内存分配有点不同。您现在可以控制这些内存位置的确切大小和生命周期。如果你不释放它,你会遇到内存泄漏,这可能会导致你的应用程序崩溃,因为在某些时候,系统无法分配更多的内存。

    int* func() {
        int* mem = malloc(1024);
        return mem;
    }
    
    int* mem = func(); /* still accessible */
    

    在上面的示例中,即使函数终止,分配的内存仍然有效且可访问。当你用完内存后,你必须释放它:

    free(mem);
    

    【讨论】:

    • 确定你可以控制变量的生命周期......你是决定范围的人,对吧?
    • -1 这个答案是错误的。你混淆了staticautomatic 变量。
    • 您自己的句子是:“静态分配意味着,您的变量的内存是自动分配的”这是错误乙>。看看manual page for GNU's libc 对此有何评论。
    • 堆栈分配不是静态的。它在运行时动态发生,并且取决于程序的运行时条件,而不是它的静态已知属性(这就是 static 在 C 和编程中的一般含义)。 编译器 可以推断静态分配,而无需实际运行程序。我认为你应该改写你的答案。
    • @EliBendersky 现在改写了。现在检查它是否正确。
    【解决方案4】:

    静态内存分配是在编译期间执行pf程序之前分配的内存。 动态内存分配是在运行时程序执行期间分配的内存。

    【讨论】:

      【解决方案5】:

      静态内存分配动态内存分配的区别

      在程序开始执行之前分配内存 (编译期间)。
      内存是在程序执行期间分配的。

      执行期间不执行内存分配或释放操作。
      内存绑定在执行期间建立和销毁。

      变量保持永久分配。
      仅在程序单元处于活动状态时分配。

      使用栈和堆实现。
      使用数据段实现。

      访问变量需要指针。
      不需要动态分配的指针。

      比动态执行更快。
      执行比静态慢。

      需要更多内存空间。
      所需的内存空间更少。

      【讨论】:

      • 静态内存分配在栈上,而动态内存分配在堆上
      • @UsmanKurd 关于静态内存,这通常是不正确的。看我的回答。
      【解决方案6】:

      静态内存分配。分配的内存将在堆栈中。

      int a[10];
      

      动态内存分配。分配的内存将在堆中。

      int *a = malloc(sizeof(int) * 10);
      

      并且后者应该是免费的d,因为 C 中没有垃圾收集器(GC)。

      free(a);
      

      【讨论】:

      • 栈上的内存是动态的,如何在栈上分配静态内存?变量可以随时“弹出”...
      【解决方案7】:

      静态内存分配:编译器为声明的变量分配所需的内存空间。通过使用运算符的地址,获得保留地址,并可以将该地址分配给指针变量。由于大多数声明的变量都有静态内存,这种将指针值分配给指针变量的方式称为静态内存分配。内存是在编译期间分配的。

      动态内存分配:它使用malloc()或calloc()等函数动态获取内存。如果这些函数用于动态获取内存并且这些函数返回的值被分配给指针变量,这种分配称为动态内存分配。内存是在运行时分配的。

      【讨论】:

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