正确使用malloc

时间:2011-09-02 12:43:33

标签: c linux malloc

我正在阅读的书中的一章专注于使用malloc linux函数分配空间的内存管理。

在我读这篇文章之前,我会在没有分配空间的情况下编写相对较小的程序。

对于内存占用率低于50MB的应用程序,不对内存分配做任何事情是否可以接受?不这样做的后果是什么?

4 个答案:

答案 0 :(得分:4)

我认为答案缺少重要的一点。存储器的大小是相对特定的技术细节,这不是主要的兴趣。关键的区别在于自动动态存储之间以及相关的生命周期:

  • 自动存储在示波器末尾结束。

  • 动态存储以malloc()开头,以free()结尾,完全由用户自行决定(并负责)。

如果可以,如果有意义,一切都应该是自动的。这需要局部性和明确定义的接口。但是,在C语言中(不是在C ++中),有时候需要讨论非本地范围的对象。那是我们需要动态分配的时候。

主要的例子是典型的链表。该列表由节点组成:

typedef struct node_tmp
{
  int data;
  struct node_tmp * next;
  struct node_tmp * prev;
} node;

现在谈谈这样一个列表归结为谈论它的任何节点并沿着prev / next指针进行衔接。但是,实际节点不能合理地成为任何本地范围的一部分,因此它们通常是动态分配

node * create_list()
{
  node * p = malloc(sizeof node);  // [1]
  p->prev = p->next = 0;
  return p;
}

void free_list(node * p) // call with head node
{
  while (p->next)
  {
    node * tmp = p;
    p = p->next;
    free(tmp);                     // [2a]
  }
  free(p);                         // [2b]
}

void append_to_end(node * p, int data); // etc.

此处列表节点存在于任何范围之外,您必须使用malloc()手动将它们生效,并在完成后进行清理。

即使在最小的程序中也可以使用链接列表,但手动分配并没有真正的方法。


编辑:我想到了另一个应该真正说服你的例子:你可能认为你可以用自动分配的节点制作列表:

node n1, n2, n3;      // an automatic linked list
n1.prev = n3.next = 0;
n1.next = &n2; n2.prev = &n1; n2.next = &n3; n3.prev = &n2;

但请注意,你不能动态地这样做! “动态”表示“在运行时”,但自动变量必须在编译时完全确定。

假设您想要一个从用户读取整数的程序。如果它是偶数,你将它添加到列表中,如果它是奇怪的你忽略它,如果它是零你停止。您无法实现具有自动分配的此类程序,因为分配需求仅在运行时确定。

在这种情况下,您需要malloc()

答案 1 :(得分:3)

如果你没有malloc用于小型应用程序,你可能不需要使用任何堆空间。小实用程序或玩具程序通常不会。当你应该使用堆时,你可能会做错的事情是:

  1. 阵列。如果你发现自己分配大型数组只是为了确保一切都适合'那么你应该使用malloc。至少,处理一切溢出的错误情况,以检查它们是否足够大。使用动态分配的数组,如果您发现需要更多空间,可以动态制作更大的数组。

  2. 做太多的递归。 C有时会将递归归结为数组循环,因为与函数语言不同,它无法正确地优化事物。如果你通过调用函数批来创建它来获得存储空间,这非常危险(程序可能会在某一天崩溃)。

  3. 使用静态对象池(结构,类)。也许你有一个环形缓冲区,可以有15个对象,你可以静态分配它们,因为你知道你的缓冲区永远不会超过15个条目。这没关系,但通过添加更多使用malloc创建的结构,允许缓冲区增长更多可能会很好。

  4. 可能有更多情况下,不需要malloc的程序可以从添加它中受益。

答案 2 :(得分:1)

应用程序的大小和malloc()的使用是两个独立的事情。 malloc()用于在运行时分配内存,当编译时不知道大小时。

无论如何,如果您确实知道要使用的结构的最大大小,则可以静态分配它们并构建应用程序而不使用malloc()。太空关键软件就是此类应用的一个例子。

答案 3 :(得分:1)

您可能在编译时静态分配内存,但不是动态分配内存。

静态分配所有内容时可能出现的问题是:

  • 你浪费记忆,因为你总是分配一个保证金的上限。
  • 在某些情况下,您的应用程序将耗尽内存(例如,因为您的估计是错误的),并且由于您无法在运行时添加新的内存资源,因此它可能是致命的。

话虽如此,在某些情况下,如实时嵌入式系统,在运行时不动态分配任何内存是要求。 (因为你有硬内存限制,或者因为分配内存可以实时破坏)