我有此代码:
#include <malloc.h>
int main()
{
int x = 1000;
//~600kb memory at this point
auto m = (void**)malloc(x * sizeof(void*));
for (int i = 0; i < x; i++)
m[i] = malloc(x * sizeof(void*));
for (int i = 0; i < x; i++)
free(m[i]);
free(m);
//~1700kb memory at this point
return 0;
}
程序开始时的内存消耗约为600kb,结束时约为1700kb。是内存泄漏还是什么?
答案 0 :(得分:6)
malloc()
使用各种特定于平台的方法从系统获取内存。但是free()
不一定总是将内存还给系统。
您看到的行为可能存在的一个原因是,当您第一次调用malloc()
时,它将要求系统提供“大块”内存,例如1 MB。随后的调用将从相同的1 MB块中完成,直到用完为止,然后将分配另一个块。
几乎没有理由立即将所有分配的内存返回给系统,只是因为应用程序不再使用它。确实,最可能的可能性是(a)应用程序请求更多的内存,在这种情况下,可以将最近释放的内存块再次分发出去,或者(b)应用程序终止,在这种情况下,系统可以有效地清理所有已分配的内存一次操作即可记忆。
答案 1 :(得分:4)
是内存泄漏还是什么?
不。每个malloc
都与一个free
匹配,如果我不错过任何内容,则不会造成内存泄漏。
请注意,您在流程管理器中看到的是分配给流程的内存。这不一定等于进程实际使用的内存。调用free
时,操作系统不会立即收回它。
如果您的代码更复杂,则可以使用valgrind之类的工具检查其是否泄漏。不过,最好不要使用手动内存管理,而应使用std容器(例如,std::vector
用于动态数组)。
答案 2 :(得分:1)
free()
和malloc()
是您的标准库的一部分,它们的行为取决于实现。该标准不需要free()
将获得的内存释放回操作系统。
如何保留内存是特定于平台的。在POSIX系统上,可以使用mmap()
和munmap()
系统调用。
请注意,大多数操作系统实现 Paging (分页),无论如何都以块的形式分配内存。因此释放每个单个字节只会带来性能开销。
答案 3 :(得分:0)
在操作系统管理下运行应用程序时,以C / C ++之类的语言进行的内存分配过程是双重的。首先,实际上需要从操作系统将内存映射到进程中。这是通过特定于OS的调用完成的,应用程序无需为此而烦恼。在Linux上,此调用为sbrk
或mmap
,具体取决于多个因素。但是,C ++代码无法直接访问此操作系统所需的内存,因此无法对其进行控制。相反,C ++运行时对其进行管理。
第二件事实际上是提供指向C / C ++代码的可用指针。当C ++代码要求时,也可以由运行时完成。
当C / C ++代码调用malloc
(或new
)时,C ++运行时首先确定在它的管理下它是否有足够的连续内存来提供指向它的指向应用程序代码的指针。 malloc
/ new
内部的效率优化使该过程变得更加复杂,效率优化通常根据对象的大小提供几个分配区域,但我们不再赘述。如果有的话,内存区域将被标记为由应用程序使用,并且指针将返回到代码。
如果没有可用的内存,则会从OS请求一块内存。块的大小通常会比请求的大小大得多-因为从OS进行请求很昂贵!
当内存为delete
d / free
d时,C ++运行时将其回收。它可能决定将内存返回给OS(例如,如果计算机上的总内存消耗很大),或者它可以将其存储以供将来使用。很多时候,直到进程退出,内存才永远不会返回给操作系统,因此,即使代码delete
/ free
都完成了任务,任何OS级工具都将显示进程消耗的内存!
还值得注意的是,通常应用程序可以绕过C ++运行时从OS请求内存。例如,在Linux上,可以通过mmap
调用来完成,或者在奇怪的情况下,可以通过sbrk
来完成-但是在后一种情况下,此后您将无法使用运行时内存管理。如果使用这些机制,您将立即看到进程内存消耗随每个内存请求或返回而增加或减少。