静态内存分配 vs 动态内存分配

9
在块作用域中使用静态关键字与使用malloc相比有什么优势?
例如:
函数 A:
f() {
    static int x = 7;
}

函数 B:

f() {
    int *x = malloc(sizeof(int));
    if (x != NULL)
        *x = 7;
}

如果我理解正确的话,这两个程序都创建了一个存储在堆上的整数7。在A中,变量是在主方法执行之前在某些永久存储中创建的。在B中,您在调用函数时即时分配内存,然后将7存储在指针所指向的位置。在什么情况下会使用其中一种方法?我知道你不能在函数A中释放x,那么B是否更可取?


1
在你的函数A中,静态变量不会存储在堆栈中 - Krishnabhadra
你现在的程序有内存泄漏问题 - 每次调用f()都会造成内存泄漏。我想这是一个应该避免的原因! - John3136
它们完全不是为了相同的目的而存在。在函数A中,整数7被存储在静态区域(在编译期间分配,而不是在堆栈上!)。它仅被分配一次,而在函数B中,当调用func B时,你将分配一个整数。 - user1149862
7个回答

7
两种程序都创建了存储在堆上的整数7。
不,它们没有。static创建具有静态存储期的对象,该对象在程序的整个生命周期中保持活动状态。而动态分配的对象(由malloc创建)将保留在内存中,直到通过free显式删除为止。两者提供独特的功能。static在函数调用中维护对象的状态,而动态分配的对象则不会。
在什么情况下可能使用一种方法而不是另一种方法?
当您希望对象在程序的整个生命周期中保持活动状态并在函数调用中维护其状态时,可以使用static。如果您正在使用多线程环境,则相同的static对象将与所有线程共享,因此需要同步。
当您明确想要控制对象的生命周期时,请使用malloc。例如:确保对象在函数调用后访问调用者之前足够长的时间存在。(自动/本地对象将在函数结束的作用域{ }结束时被释放)。除非调用者显式调用free,否则分配的内存将泄漏,直到操作系统在程序退出时重新获取它。

1
你不想更多地使用malloc吗?因为它可以让你在需要时释放内存,这样更灵活。或者有些情况下,你需要变量永久存在吗? - CowZow
@CowZow:这取决于您想要实现的功能,例如:有时您需要一个计数器来跟踪整个程序生命周期中的某些内容,那么static将是自然选择。此外,重要的是要注意动态内存使用除了更容易出现可用性错误外,还具有一定的性能开销。所以,因材施教是原则。 - Alok Save

0
在函数A中,您正在分配具有静态存储期的x,这通常意味着它不在堆上(大多数人认为的)。相反,它只是保证在程序运行期间存在的内存。
在函数B中,每次进入函数时都要分配存储空间,然后(除非有一个您没有显示的free)泄漏该内存。
仅考虑这两个选择,函数A显然更可取。它有缺点(尤其是在多线程情况下),但至少在某些情况下是正确的。函数B(目前)就是完全错误的。

0

0
首先,static是一种存储类,而malloc()是一个API,它触发brk()系统调用以在堆上分配内存。

如果我理解正确,两个程序都创建了一个存储在堆上的整数7?

不是的。静态变量存储在程序分配的内存数据段中。即使静态变量的作用域结束,它仍然可以在其作用域之外访问,这可能表明数据段的内容具有独立于作用域的生命周期。

在什么情况下会使用其中一种方法而不是另一种方法?

如果您想在给定范围内更好地控制内存使用,请使用malloc()/free(),否则更简单(更干净)的方法是使用静态变量。
就性能而言,声明静态变量比在堆上分配要快得多。因为堆管理算法复杂,服务堆请求所需的时间取决于算法类型。
我认为建议使用静态变量的另一个原因是,静态变量默认初始化为零,因此少了一件事需要担心。

0

忘记堆栈和堆。这里发生的最重要的事情不是那个。

有时候static修改作用域,有时候它修改生命周期。原型示例:

void int foo() {
     static int count = 0;
     return count++;
}

尝试反复调用此函数,甚至从几个不同的函数或文件中调用,您会发现count不断增加,因为在这种情况下,static使变量的生命周期等于整个程序的执行时间。


0
如果我理解正确,两个程序都创建了一个存储在堆上的整数7。 不是的,静态变量{{link1:被创建在数据或BSS段中},它们的生命周期贯穿整个程序的生命周期。当使用malloc()分配内存时,内存被分配在堆中,必须使用free()方法显式地释放。 在什么情况下可能会使用其中一种方法而不是另一种方法? 当你想要多次调用同一个函数访问相同的变量时,可以使用第一种方法。也就是说,在你的例子中,x只会初始化一次,当你第二次调用该方法时,将使用同一个x变量。 当你不希望在多次调用函数时共享变量时,可以使用第二种方法,这样当第二次调用该函数时,x会被重新malloc。每次使用完x后都必须释放它。 你可以通过连续两次调用f()来看到两种f()的区别。
...
f();
f();
...

f(){
    static int x = 7;
    printf("x is : %d", x++);
}

f(){
   int *x = malloc(sizeof(int));
   if (x != NULL)
      *x = 7; 
   printf("x is : %d", (*x)++);
   free(x);   //never forget this,
}

结果将会不同


0
考虑以下示例以了解静态变量的工作原理。通常,我们使用静态关键字来定义变量或函数的范围。例如,定义为静态的变量将受限于函数内部并保留其值。
但是,如下所示的示例程序,如果您将静态变量的引用传递给任何其他函数,则仍然可以从任何其他函数更新相同的变量。
但是,准确地说,当程序终止时,静态变量会死亡,这意味着内存将被释放。
#include <stdio.h>

void f2(int *j)
{
    (*j)++;
    printf("%d\n", *j);
}

void f1()
{   
    static int i = 10;
    printf("%d\n", i);
    f2(&i);
    printf("%d\n", i);  
}

int main()
{
    f1();       
    return 0;   
}

但是在使用malloc()的情况下,除非程序员在程序终止之前使用free()释放内存,否则内存将不会在程序终止时被释放。

这样使用malloc()可以使您感觉对变量寿命有控制,但要小心......当您选择动态内存分配时,必须非常精确地分配和释放内存。 如果您忘记释放内存并且程序终止,那么堆的那部分就不能被其他进程用来分配内存。这可能会导致实际场景中的内存不足并减慢计算速度。要摆脱这种情况,您必须手动重新启动系统。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接