C语言程序退出后,malloc()申请的内存会被操作系统自动回收吗?

几乎每一个C语言程序员都明白,调用 malloc() 函数申请的内存用完要释放,否则就会造成内存泄漏,这可能导致程序崩溃。不过,初学者可能还会有比较迷惑的地方,例如,malloc() 函数申请的内存,如果没有显式的调用 free() 释放,C语言程序退出后(不管是崩溃退出,还是正常退出),会被自动释放吗?

例如下面这段C语言程序:

...
int main () {
  int *p = malloc(10 * sizeof *p);
  *p = 42;
  return 0;
}

程序退出之前,并未显式的调用 free() 函数是否 p,那么这会导致内存泄漏吗?或者说,操作系统会在它结束运行后,回收相关资源吗?

C语言程序退出后,资源会被自动释放吗?

一般来说,现代绝大多数操作系统都会在其退出运行后清理其相关资源,包括打开的文件,申请的内存等等。

这是必要的,否则操作系统会随着时间的推移逐步丢失资源,这不利于操作系统长期稳定的运行。如果程序员编写程序不当,哪怕只有一点泄漏资源的情况发生,都可能导致操作系统必须重新启动。

不过,虽说大多数操作系统会在C语言程序终止运行后回收相关资源,但是我们不能依赖它,在C语言程序开发中,显式的释放不再使用的资源是常用的做法。

显式释放资源

操作系统只能回收一些“标准”资源,例如分配的内存段,被C语言程序打开的文件等。对于一些C语言程序产生的临时文件,或者对外部资源状态的修改,操作系统可能就无能为力了,这些资源的释放只能依靠程序员处理,这通常与释放内存结合在一起。

如果我们期望编写的C语言程序能够长期运行,例如该C语言程序是某种服务(守护进程),它需要在处理其他单元发出的多个请求时保持运行,那么显然不能再指望操作系统帮忙回收废弃的资源。

总不能定时重启我们的C语言程序吧。

有时,不推荐显式释放资源

在一些特殊的C语言程序开发中,有时并不推荐显式的释放资源。例如,某个C语言程序在内存中申请了一个大缓存,当它退出时,如果显式的调用 free() 函数释放这个大缓存,那么系统将不得不遍历整个缓存结构,逐次释放内存片段(大缓存一般会切分成若干个片段给程序不同的子模块使用),这样做其实毫无意义,而且会浪费资源。

原因是简单的,要释放的资源其实已经是废弃的资源了,无论对于C语言程序本身,还是操作系统来说都是如此。所以,怎样释放它已经无关紧要了,如果能够交给操作系统快速的释放,那么又何必花时间花精力“精细”的逐次释放呢?

特别是,如果操作系统已经将包含这段大缓存的内存页交换到磁盘上,那么如果C语言程序通过遍历结构释放它,实际上也将所有的这些页又一次全部加载到内存中了,这会浪费大量的时间和精力,但是没有任何实际的好处,甚至可能导致操作系统中的其他程序被调出。

简言之,有时候不显式的释放资源,反而能够提升操作系统的效率。当然,这要建立期望被释放的资源能够完全被操作系统处理的基础上。

事实上,有一些高性能的服务器在处理请求时,会为每一个请求创建新进程工作,然后在完成时让它退出。服务器不必跟踪内存分配,也不必执行释放和垃圾回收,因为在进程结束时,所有的废弃资源都会被操作系统统一处理,这无疑提升了服务器的效率。

小结

绝大多数现代操作系统都会在进程终止运行后,回收其资源,但是作为C语言程序员,我们不能依赖操作系统。本文在最后还讨论了一种不建议显式释放资源的例子,但是读者应该明白背后的原因,然后在自己的程序开发中,酌情考虑究竟是否应该显式释放内存。低开销,高效率,始终是C语言程序员应该追求的目标。

阅读更多:   C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif