跳转到内容

内存管理/手动内存管理

50% developed
来自维基教科书,开放的书籍,为一个开放的世界

在每个应用程序中,您必须在使用之前分配新的存储空间,然后在完成使用后必须将所有这些存储空间返回给操作系统。虽然一些语言会为您处理所有这些,但像C或C++这样的低级语言有时需要程序员付出更多努力来管理内存。有几种方法可以做到这一点:隐式和显式。

隐式内存分配是内存,通常在系统堆栈上,由编译器分配。当您创建新变量时,就会发生这种情况

void my_func(void) {
  int x;
  char y;
  int z[25];
  ...
}

在这里,当函数被调用时,在系统堆栈上为变量xyz分配空间,并且当函数退出时,空间会自动回收。

显式内存分配是通过指针,以及对内存管理函数的调用

#include <stdlib.h>
void my_func(void) {
  int * z;
  z = (int *)malloc(25);
  ...
}

在这里,我们仍然有变量z,它仍然被用作 25 个整数的数组。但是,当函数退出时,此存储空间不会自动回收。这有一个额外的好处,即以这种方式创建的数组可以从函数中返回

正确 错误
int *my_func(void) {
  int * x;
  x = (int *) malloc(25);
  return x;
}
int *my_func(void) {
  int x[25];
  return x;
}

为什么一种方式正确,而另一种方式错误?答案是范围:在左侧的示例中,数组是在堆上创建的,并且内存不会在函数退出后被回收。这意味着内存仍然可以使用,即使在函数返回之后也是如此。然而,在右侧的示例中,内存是在堆栈上分配的,并且在函数退出时会消失。

还有很多地方需要在编译时未知的大小创建内存。考虑一个需要分配足够的存储空间来存储下载的网页 HTML 文本的网页浏览器。由于网页的大小可能各不相同,因此我们不可能在编译时知道它们的大小,我们必须在运行时使用malloc或等效函数来分配存储空间。

在堆栈上分配的内存,其大小和范围是固定的,称为静态。使用malloc在运行时分配的内存称为动态

释放动态内存

[编辑 | 编辑源代码]

当您使用malloc或类似方法从堆中分配内存时,您会从系统获得指向分配内存的指针。当您完成使用时,必须释放内存,将其返回给系统。未能返回您分配的所有内存称为内存泄漏。在 C 中,您可以使用free()函数释放内存。

内存管理问题

[编辑 | 编辑源代码]

当您分配内存时,您必须始终注意将分配的内存释放回系统。问题在于:如果您的系统很复杂,需要分配许多小的内存块,您需要确保也释放所有这些单独的小块。如果您处于动态情况,内存不断被分配和释放,并且内存块必须保持可用以随机长度的时间,那么这可能更加困难。

为了克服这些复杂情况,可以使用自动内存管理器系统,如垃圾收集器,来尝试自动执行内存分配和释放。

华夏公益教科书