正确使用malloc

正确使用malloc,c,linux,malloc,C,Linux,Malloc,我一直在读的书中有一章重点介绍了使用malloclinux函数分配空间的内存管理 在我读这篇文章之前,我会在不分配空间的情况下制作相对较小的程序 对于内存占用量保持在50MB以下的应用程序,不进行任何内存分配是可以接受的吗?不这样做的后果是什么?应用程序的大小和malloc的使用是两件独立的事情。当编译时大小未知时,malloc用于在运行时分配内存 无论如何,如果您确实知道要使用的结构的最大大小,那么您可以静态地分配它们并构建应用程序,而无需使用malloc。空间关键型软件就是此类应用的一个例子

我一直在读的书中有一章重点介绍了使用malloclinux函数分配空间的内存管理

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


对于内存占用量保持在50MB以下的应用程序,不进行任何内存分配是可以接受的吗?不这样做的后果是什么?

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


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

应用程序的大小和malloc的使用是两个独立的因素。当编译时大小未知时,malloc用于在运行时分配内存


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

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

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

你是在浪费内存,因为你总是分配一个有余量的上限。 在某些情况下,您的应用程序将耗尽内存,例如,因为您的估计是错误的,并且由于您无法在运行时添加新的内存资源,因此可能会导致致命的后果。
也就是说,在某些情况下,如实时嵌入式系统,不需要在运行时动态分配任何内存。因为您有硬内存限制,或者因为分配内存会破坏实时性,所以您可能是在编译时静态分配内存,而不是动态分配内存

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

你是在浪费内存,因为你总是分配一个有余量的上限。 在某些情况下,您的应用程序将耗尽内存,例如,因为您的估计是错误的,并且由于您无法在运行时添加新的内存资源,因此可能会导致致命的后果。
也就是说,在某些情况下,如实时嵌入式系统,不需要在运行时动态分配任何内存。因为您有硬内存限制,或者如果小型应用程序不使用malloc,分配内存可能会破坏实时性,所以您可能不需要使用任何堆空间。小实用程序或玩具程序通常不会。但是,当您应该使用堆时,您可能会做错事:

数组。如果您发现自己分配大型阵列“只是为了确保一切都适合”,那么您可能应该使用malloc。至少,处理所有内容都溢出的错误条件,以检查它们是否真的足够大。使用动态分配的阵列,如果您发现需要更多的空间,您可以动态生成更大的阵列

做太多的递归。C得益于有时将递归平坦化为数组上的循环,因为与函数语言不同,它不能正确地优化事物。如果您通过调用函数lots来创建存储空间,那么有一天程序可能会在您身上崩溃,这是非常危险的

使用对象、结构、类的静态池。也许你有一个环形缓冲区,15个可能在其中的对象,你静态分配它们,因为你知道你的缓冲区永远不会有超过15个条目。这还可以,但是通过添加更多用malloc创建的结构,允许缓冲区增长得更多,这可能会更好


在很多情况下,不需要malloc的程序可以从添加malloc中获益。

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

数组。如果您发现自己分配大型阵列“只是为了确保一切都适合”,那么您可能应该使用malloc。至少,处理所有内容都溢出的错误条件,以检查它们是否真的足够大。使用动态分配的阵列,如果您发现需要更多的空间,您可以动态生成更大的阵列

做太多的递归。C得益于有时将递归平坦化为数组上的循环,因为与函数语言不同,它不能正确地优化事物。如果您通过调用函数lots来创建存储空间,那么有一天程序可能会在您身上崩溃,这是非常危险的

使用对象、结构、类的静态池。也许您有一个环形缓冲区和15个对象 这可能就在它里面,你可以静态地分配它们,因为你知道你的缓冲区永远不会有超过15个条目。这还可以,但是通过添加更多用malloc创建的结构,允许缓冲区增长得更多,这可能会更好


可能更多的情况下,不需要malloc的程序可以从添加malloc中获益。

我认为答案遗漏了一个要点。内存大小是一个相对具体的技术细节,它不是主要的兴趣。关键的区别在于自动存储和动态存储以及相关的生存期:

自动存储在作用域的末尾结束

动态存储从malloc开始,到免费结束,完全由用户自行决定和负责

如果你能,如果它有意义,一切都应该是自动的。这需要局部性和定义良好的接口。然而,在C中,C++中没有那么多的时候需要讨论关于范围的局部对象。这时我们需要动态分配

最好的例子是典型的链表。该列表由以下节点组成:

typedef struct node_tmp
{
  int data;
  struct node_tmp * next;
  struct node_tmp * prev;
} node;
现在讨论这样一个列表可以归结为讨论它的任何节点,并沿着上一个/下一个指针进行分类。但是,实际节点不能合理地成为任何本地作用域的一部分,因此它们通常是动态分配的:

在这里,列表节点存在于任何范围之外,您必须使用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开始,到免费结束,完全由用户自行决定和负责

如果你能,如果它有意义,一切都应该是自动的。这需要局部性和定义良好的接口。然而,在C中,C++中没有那么多的时候需要讨论关于范围的局部对象。这时我们需要动态分配

最好的例子是典型的链表。该列表由以下节点组成:

typedef struct node_tmp
{
  int data;
  struct node_tmp * next;
  struct node_tmp * prev;
} node;
现在讨论这样一个列表可以归结为讨论它的任何节点,并沿着上一个/下一个指针进行分类。但是,实际节点不能合理地成为任何本地作用域的一部分,因此它们通常是动态分配的:

在这里,列表节点存在于任何范围之外,您必须使用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 malloc是C的一部分,而不是Linux。2你应该学习一些C编程的基础知识,理解动态分配以及为什么需要它——程序大小与此无关。3为什么这个标记为C++?在开始学习之前先选择一种语言。OP没有提到程序大小。而且它并没有被标记为C++,尽管我希望我们有OP来澄清和学习正确的标记;谢谢你,基利安。@Tomalak:OP说相对较小的程序和metions内存占用。这个标签提到了问题的早期修订。@Kerrek:很确定他的意思是简单/快速/不复杂,通常伴随少量代码。在最后一段,现在

“编辑”引用的是内存占用,而不是可执行文件的大小。@Tomalak:但所有这些都缺少一个要点,即生命周期。当您需要其生存时间必须超过本地范围的内存时,您可以动态地进行分配。这在最小的程序中也是必要的,这取决于你在做什么。1 malloc是C的一部分,而不是Linux。2你应该学习一些C编程的基础知识,理解动态分配以及为什么需要它——程序大小与此无关。3为什么这个标记为C++?在开始学习之前先选择一种语言。OP没有提到程序大小。而且它并没有被标记为C++,尽管我希望我们有OP来澄清和学习正确的标记;谢谢你,基利安。@Tomalak:OP说相对较小的程序和metions内存占用。这个标签提到了问题的早期修订。@Kerrek:很确定他的意思是简单/快速/不复杂,通常伴随少量代码。在最后一段中,再次提到了“现在编辑的内存占用”,而不是可执行文件的大小。@Tomalak:但所有这些都缺少了要点,即生命周期。当您需要其生存时间必须超过本地范围的内存时,您可以动态地进行分配。即使是在最小的程序中,这也是必要的,这取决于你在做什么。好的,关于malloc的使用,有什么共同的约定值得遵循吗?有没有一个简单的方法来估计你需要分配多少?调用堆栈大小是如何设置的?@a:为什么您永远不知道需要分配多少?如果你试图创建一个大小为n的int数组,你只需要说int*arr=int*mallocn*sizeofint;此外,您并不总是需要进行动态内存分配。只是有些时候没有其他方法可以做到,这是有道理的。当我不需要动态分配内存时,我将如何确定可用的堆栈大小?通常,您不需要这样做。如果您有任何理由担心堆栈大小,请使用动态分配,方法是敲入一些大对象的指针,并在运行时初始化它们。@a:如果您正在分配的内存量使您担心可用堆栈大小,那么您可能应该执行动态内存分配。堆栈通常至少有50千字节,而且通常更多。如果您要分配一个50000字符的字符数组,那么您应该进行动态内存分配。好的,关于malloc的使用有什么好遵循的通用约定吗?有没有一个简单的方法来估计你需要分配多少?调用堆栈大小是如何设置的?@a:为什么您永远不知道需要分配多少?如果你试图创建一个大小为n的int数组,你只需要说int*arr=int*mallocn*sizeofint;此外,您并不总是需要进行动态内存分配。只是有些时候没有其他方法可以做到,这是有道理的。当我不需要动态分配内存时,我将如何确定可用的堆栈大小?通常,您不需要这样做。如果您有任何理由担心堆栈大小,请使用动态分配,方法是敲入一些大对象的指针,并在运行时初始化它们。@a:如果您正在分配的内存量使您担心可用堆栈大小,那么您可能应该执行动态内存分配。堆栈通常至少有50千字节,而且通常更多。如果要分配50000个字符的字符数组,那么应该进行动态内存分配。