不使用malloc是否可能造成内存泄漏?

4
这个问题如标题所述: 是否可能在不使用任何内核特定手段(如malloc、new等)的情况下产生内存泄漏?
如果我在一个函数内创建了一个有很多元素的链表,然后在退出函数时没有清理该链表,那么该链表将被创建而没有使用任何malloc调用。
struct list_head {
     struct list_head *next, *prev;
}

在退出此函数后,所有资源是否都能得到释放?这样我就可以自由地执行它一百万次,而不会有任何泄漏吗?

主题:如果您没有使用特定的malloc或new调用,则不会发生堆内存泄漏。永远不会。是这样吗?


你的示例中没有任何字符串在堆栈上。对于第一个字符串,只有指针在堆栈上,实际的字符串在其他地方。如果你在声明时给第二个字符串(string2)赋值,它本来会在堆栈上,但现在你只会得到编译错误。 - Some programmer dude
关于内存泄漏。只有在分配了某些东西,但从未释放它时才会发生内存泄漏。比如打开文件但不关闭它,或使用mallocnew分配内存,但不使用freedelete释放它。 - Some programmer dude
6
“堆栈”这个词汇起码可以作为一个临时替代品,但最糟糕时会误导人。最严重的是,在讨论的问题中完全没有必要使用这个词汇。 - Kerrek SB
你正在看牛的错误部位。相反,问一下什么构成了“释放内存”或“内存管理”。因为list_head不是一个函数(所以它永远不会泄漏),指针通常意味着动态内存分配。你应该问“谁负责释放这个内存和何时释放”。(而问题的答案是:是的。只需使用mmap即可) - sehe
显示剩余6条评论
5个回答

12

泄漏总是和资源相关联。资源的定义是你手动获取的东西,必须手动释放。内存是一个主要的例子,但还有其他资源,如文件句柄、互斥锁、网络连接等。

当你获取资源,但随后丢失了处理该资源的句柄,以至于没有人可以释放它时,就会发生泄漏。泄漏的较小版本是“仍然可访问”的情况,即您不释放资源,但仍然拥有句柄并且可以释放它。这主要是由于懒惰造成的,但泄漏则总是编程错误。

由于您的代码从未获取任何资源,因此也不可能存在任何泄漏。


“has no resources” 需要更谨慎的措辞。它确实指的是资源(因此代码“具有”正在进行的资源)。但它似乎并没有拥有资源。我们无法确定,因为将节点分配给列表可能会(根据文档/定义)授予节点所有权给列表。 - sehe
@sehe:OP的代码没有获取任何资源,所以我会称之为“没有资源”——代码使用的所有数据都由环境提供。不过我会重新表述一下。 - Kerrek SB
1
可能会出现自动内存泄漏,而不需要显式请求资源 - 堆栈指针损坏,无论是有意还是无意的,都可能导致这种情况。 - SomeWittyUsername
1
@JamesKanze,无论泄漏有多频繁或者多严重,它都是泄漏。如果泄漏很小或者不太重要,它可能没有任何后果,但是如果你失去了对它的连接,它仍然是一个泄漏的定义。 - Devolus
2
@icepack:你能举个例子来说明你所想的,是语言内在的吗?(C或C++中没有“堆栈指针”) - Kerrek SB
显示剩余4条评论

1

如果您在没有使用malloc或new的情况下应用变量,则其位于内存中的堆栈空间。因此,当函数返回时,该变量将被收回。

另一方面,您使用malloc或new申请的内存位于堆空间。系统不关心您是否释放了空间。在这种情况下,如果您不使用free或delete,则会发生内存泄漏。


1
如果你没有使用特定的malloc或new调用,就不会出现堆内存泄漏。永远不会。这是正确的吗?
这种假设并不完全正确。问题在于操作系统本身(或其他第三方组件,你必须依赖它们)也可能存在内存泄漏。在这种情况下,你可能不会主动调用malloc,但会调用其他(操作系统)函数,可能会泄漏。
因此,你的假设取决于你对这种事情的看法。你可以认为操作系统/第三方实现不属于你的范围,那么这个假设就是正确的。如果你有一个明确定义的系统,并且你的要求是必须保证一定的运行时间,则可能需要考虑这样的问题。
所以这个问题的答案是:
是否可能在不使用malloc的情况下造成内存泄漏?
是的,可能会。

0

malloc()从堆上分配内存,而字符串和结构体常量(string1string2以及那些list_head)的空间将在编译时在堆栈上保留。

实际上,程序所分配的任何内存(堆或栈)都将在进程退出时(至少在*nix系统中)由内核回收。

我会把内存泄漏定义为在堆上分配内存且在程序退出时未释放它。这个定义实际上回答了你的问题。

有一些标准函数(如strdup)会在堆上分配内存,请注意。


0

另一个分配后忘记释放的资源示例:

如果你在使用OpenGL,并且调用了glGenBuffers()一百万次而没有相应的glDeleteBuffers调用,那么你很有可能会用完VRAM,你的图形驱动程序将开始向系统内存泄漏。

我刚刚遇到了这种情况。幸运的是,Visual Studio的内存分析器让它变得相当容易找到。它显示为外部进程nvoglv32.dll进行的大量分配。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接