正确使用malloc

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

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

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

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

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

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

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

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

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

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

  • 动态存储以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()

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

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

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

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

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

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