操作系统只会恢复它(在程序退出后)对吗?那么除了好的编程风格还有什么用呢?还是我有什么误解?它与“自动”分配有何不同,因为两者都可以在运行时更改,并且都在程序执行后结束?
8 回答
当您的应用程序处理大量数据时,您必须释放以节省堆空间。如果你不这样做,可能会发生一些不好的事情:
- 操作系统将停止为您分配内存(崩溃)
- 操作系统将开始将您的数据交换到磁盘(抖动)
- 其他应用程序将有更少的空间来放置他们的数据
操作系统收集应用程序退出时分配的所有空间这一事实并不意味着您应该依靠它来编写可靠的应用程序。这就像试图依靠编译器来优化糟糕的编程一样。内存管理对于良好的性能、可扩展性和可靠性至关重要。
正如其他人所提到的,malloc
在堆中分配空间,而在堆栈上创建自动变量。两者都有用途,但它们确实非常不同。堆空间必须由操作系统分配和管理,并且可以动态存储不同大小的数据。
在 C/C++ 中,“自动”变量在堆栈上分配。它们在函数的出口处被销毁。这将自动发生。你不需要为此写任何东西。
堆分配(调用的结果malloc
)要么显式释放(调用),要么free
在进程结束时被清理。
如果您正在编写可能会使用一次或两次的小程序,那么可以不释放您的堆分配。这不好,但可以接受。
如果您正在编写中型或大型项目或计划将您的代码包含到其他项目中,那么您绝对应该释放每个堆分配。不这样做会造成巨大的麻烦。堆内存不是无穷无尽的。程序可能会使用它。即使您将分配少量内存,这仍然会对操作系统造成不必要的压力,导致交换等。
底线:释放分配不仅仅是一种风格或一个好习惯。
这是一种很好的编程风格,而且不止于此。在非平凡的程序中不进行适当的内存管理最终会影响程序的可用性。当然,操作系统可以在程序终止后回收您分配/使用的任何资源,但这并不能减轻程序执行期间的负担或潜在问题。
考虑一下你用来发布这个问题的网络浏览器:如果浏览器是用需要内存管理的语言编写的,而代码没有正确执行,你认为它会在你注意到之前多久它正在吃掉你所有的记忆?您认为浏览器可以使用多久?现在考虑一下用户经常让浏览器长时间打开:如果没有适当的内存管理,它们会在几次页面加载后变得无法使用。
如果你在不使用 free() 的情况下调用一个宏一千次,那么编译器或安全的说法系统会给你分配一千个不同的地址,但是如果你在每个 malloc 之后使用 free(),那么每次只会给你一个内存地址。因此,内存泄漏、总线错误、内存超出范围和崩溃的机会将是最小的。使用 free() 是安全的。
一旦您退出定义它的范围,自动变量就会被销毁(并且它的内存是可重用的)。对于大多数比程序退出早得多的变量。
如果你malloc
不这样做free
,那么在程序退出之前内存不能重用。即便如此,在某些操作系统非常少的系统上也不会。
所以是的,自动变量和泄漏的内存分配之间有很大的区别。调用一个泄漏分配足够多次的函数,您将耗尽内存。调用带有自动变量的函数任意多次,内存是可重复使用的。
如果您的程序没有立即退出并且您没有释放内存,那么您最终会浪费它。要么您最终会耗尽内存,要么您将开始交换到磁盘(这很慢,而且也不是无限的)。
自动变量在堆栈上,它的大小应该在编译时知道。如果你需要存储你不知道的大小的数据,例如,维护一个二叉树,用户可以在其中添加和删除对象。除此之外,堆栈大小可能会受到限制(取决于您的目标),例如,linux 内核堆栈通常为 4k-8k。您还会破坏指令缓存,这会影响性能,
是的,您绝对必须在 malloc() 之后使用 free() (以及完成后关闭文件和其他资源)。虽然操作系统确实会在执行后恢复它,但长时间运行的进程会以这种方式泄漏内存。如果您的程序与运行单个方法的 main 方法一样简单,那么它可能不是什么大问题,尽管非常草率。您应该养成在 C 中正确管理内存的习惯,因为有一天您可能想编写一个运行时间超过一秒钟的重要程序,如果您不提前学习如何操作,您将有一个处理内存泄漏的巨大头痛。