静态内存分配和动态内存分配之间的区别


Answers:


90

共有三种类型的分配-静态,自动和动态。

静态分配是指在程序启动时分配变量的内存。创建程序时大小是固定的。它适用于全局变量,文件范围变量和使用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);

2
确保您可以控制变量的生存期...您是一个决定范围的人,对吗?
Luchian Grigore 2011年

当然可以,但这不是我的意思。您不能延长变量的生存期以超过其范围。但是,也许我应该在回答中加以澄清。谢谢
Constantinius

5
-1这个答案是错误的。您会混淆静态自动变量。
brice 2013年

2
您自己的句子显示为:“ 静态分配意味着,将自动分配变量的内存”。这是错误的。看看GNU libc手册页对此有何评论。
brice

1
@EliBendersky现在改写。现在检查是否正确。
Suraj Jain

115

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

动态内存分配

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

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

堆内存是持久的,直到free()被调用为止。换句话说,您可以控制变量的生存期。

自动内存分配

这就是通常所说的“堆栈”内存,当您输入新的作用域时(通常是在调用堆栈上推送新功能时)进行分配。移出作用域后,自动内存地址的值是不确定的,访问它们错误的

int a = 43;

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

静态内存分配

在编译时*分配,并且静态存储器中变量的生命周期是程序生命周期

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

extern考虑关键字时,事情变得更加有趣。当extern变量被定义为它的编译器分配存储器。当一个extern变量声明,编译器要求变量被定义在别处。声明/定义extern变量失败将导致链接问题,而声明/定义static变量失败将导致编译问题。

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

int a = 32;

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

static int a = 32;

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

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

*关于静态内存分配的注意事项

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

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

例如,编译器可能会data在已编译的二进制文件中创建一个较大的节,并且当程序被加载到内存中时,该地址位于data该程序的段将用作分配的内存的位置。这具有明显的缺点,如果使用大量静态内存,则使已编译的二进制文件非常大。可以编写由不到六行代码生成的数千兆字节的二进制文件。编译器的另一种选择是在执行程序之前注入将以其他方式分配内存的初始化代码。该代码将根据目标平台和操作系统而有所不同。在实践中,现代编译器使用启发式方法来决定使用这些选项中的哪一个。您可以编写一个小的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. */

在选择应将哪些变量放入寄存器中时,大多数现代编译器比您聪明:)

参考文献:


3
注意:建议int * a = malloc(sizeof(*a));您避免重复输入的类型a。如果进行a更改的类型,这将使​​事情变得容易得多。
Shahbaz 2013年

1
简称为堆,但与堆数据结构无关。在这种情况下,堆意味着一个混乱的地方
动态的

2
“静态内存分配...在编译时分配”您是说分配大小是在编译时确定的吗?预留内存不会仅在运行时发生吗?
lf215

2

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

动态内存分配:它使用malloc()或calloc()之类的函数动态获取内存。如果使用这些函数动态获取内存并将这些函数返回的值分配给指针变量,则这种分配称为动态内存分配。内存在运行时关联。


2

静态内存分配:

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

动态内存分配:

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

1
“静态内存分配[...]它使用的数据结构栈呼吁实现静态分配” ,这是不正确的,误导性的。请参阅我的帖子,了解自动分配和静态分配之间的区别。静态内存可能会使用堆栈。这在很大程度上取决于实现,并且多个策略可用于同一实现。我也不确定您所说的“效率低下”是什么意思。@Trieu Toan,您通过错误的编辑更改了此答案的含义。
布里斯

1

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

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

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

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

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

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

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

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


1
静态内存分配在堆栈上分配,而动态内存分配在堆上分配
Usman Kurd

@UsmanKurd对于静态内存,这通常是不正确的。看我的答案。
布莱斯

0

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


-1

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

int a[10];

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

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

由于C中没有垃圾收集器(GC),因此后者应该是免费的

free(a);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.