内存泄露专题(1)何为内存泄露

简介: 内存泄露专题(1)何为内存泄露

作为C/C++的开发者,内存泄漏问题大概是最不愿意碰到,但是却不得不去面对的一个问题。自从C/C++诞生的那一天起,内存和指针就好比天上的两朵乌云,笼罩在无数C/C++开发者的头顶,如跗骨之蛆,挥之不去。它一方面以其无与伦比的高效率以及便捷性让人可以在浩如烟海的硬件地址之间纵横驰骋,如入无人之境;另一方面却又像一个娇滴滴的小姑娘,稍不顺心遂意,就会给你致命的下马威。就如同你永远猜不透女朋友为什么会生气一样,你永远也想不到在什么地方存在着看不见摸不着的内存泄漏问题。

高收益必然伴随着高风险,古人诚不欺我。

那么,什么是内存泄漏呢?

所谓内存泄漏,就是由于程序主动申请了内存,但是又没有主动释放它,那么这块内存可能就会一直驻留在进程中,只要进程不结束,内存就一直不释放。如果这是一个长期运行的server或者daemon类的守护进程,一旦发生内存泄漏,那么后果是不可设想,因为在长时间的运行过程中,进程一点点蚕食系统内存,最终可能导致系统内存耗尽,从而导致系统崩溃。

内存泄漏问题为什么会存在呢?

对于一个进程来说,其内存占用可根据其地址范围及生命周期分为四个区域,这就是大名鼎鼎的内存四区。分别为代码区、数据区、堆区和栈区。

其中代码区主要存放二进制代码,由操作系统进行管理;数据区主要存放全局变量、静态变量以及常量,这些变量 或常量会贯穿整个进程生命周期,在程序结束后会由操作系统进行释放。栈区的空间是由编译器自动分配和释放的 ,其生命周期一般以大括号{}作为分界点,比如常见的局部变量,函数参数等,大括号结束,变量空间也就自动释放了。以上三区的内存基本上都不会造成内存泄漏。

而真正会造成内存泄漏的罪魁祸首只有堆区内存。堆区的内存有个特点,就是必须由程序员手动去申请以及释放。比如常见的malloccallocrealloc函数用来在堆上申请内存,free函数用来释放内存。C++中也用new/delete运算符来管理申请和释放内存。通常来说,有申请就必须要有释放,也就是说,malloc/freenew/delete必然是成对出现的,一旦发生了不匹配 ,那么就极有可能存在内存泄漏问题。

void foo(){
    int *p = (void*)malloc(sizeof(int));
    //do  something with pointer p
    free(p);
    p = NULL;
}

比如上面就是一段非常简单的在堆上分配内存的例子,我们在第2行使用malloc函数在堆上申请了一个大小为 sizeof(int)的内存块,在第4行对这块内存进行了释放。

如果我们把第4行注释掉,代码如下所示:

void foo(){
    int *p = (void*)malloc(sizeof(int));
    //do  something with pointer p
    //free(p);
    p = NULL;
}

当执行完 p = NULL语句后,原来申请的那一块内存也就没有指针可以指向它了,但是这块内存又还没有释放,这样就会导致这块内存再也无法释放掉,除非整个进程停止。如果这样的代码在整个程序中有很多,那么也就会有很多内存申请后指针丢失,无法释放,导致内存占用越来越大,从而形成很严重的内存泄露问题。

那么,有人问,既然堆区的内存管理这么麻烦,而栈区的内存可以由编译器自动分配和回收。我们直接用栈区的内存不就行了吗?干嘛自讨苦吃,去招惹堆区的魔鬼呢?

事实上,每个进程所能使用栈空间是极其有限的。在Linux系统上,我们可以通过ulimit -s命令查看可支配的stack空间大小,这个大小一般只有几兆,甚至kb级别。对于一个大型的应用程序来说,这点可怜的栈区内存未免显得捉襟见肘。只有对那些占用内存比较小的变量,对执行效率要求比较高的地方,可能直接使用栈上的内容,对于一些比较占用内存的结构,比如结构体、字符串等,通常的做法,都是在堆上申请内存。

这也就意味着,只要我们使用C/C++进行编程,内存泄漏的问题就是我们不得不去面对并要解决的问题。


本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对C/C++课程感兴趣的读者,可以点击链接,查看详细的服务:C/C++Linux服务器开发/高级架构师

目录
相关文章
|
7月前
|
JavaScript 前端开发 Java
内存管理和内存泄露(闭包、作用域链)(三)
内存管理和内存泄露(闭包、作用域链)
75 0
|
7月前
|
自然语言处理 JavaScript 前端开发
内存管理和内存泄露(闭包、作用域链)(二)
内存管理和内存泄露(闭包、作用域链)
53 0
|
4月前
|
JavaScript 前端开发 Java
JavaScript内存泄露大揭秘!你的应用为何频频“爆内存”?点击解锁救星秘籍!
【8月更文挑战第23天】在Web前端开发中,JavaScript是构建动态网页的关键技术。然而,随着应用复杂度增加,内存管理变得至关重要。本文探讨了JavaScript中常见的内存泄露原因,包括意外的全局变量、不当使用的闭包、未清除的定时器、未清理的DOM元素引用及第三方库引发的内存泄露。通过了解这些问题并采取相应措施,开发者可以有效避免内存泄露,提高应用性能。
68 1
|
5月前
|
存储 算法 Java
(四)JVM成神路之深入理解虚拟机运行时数据区与内存溢出、内存泄露剖析
前面的文章中重点是对于JVM的子系统进行分析,在之前已经详细的阐述了虚拟机的类加载子系统以及执行引擎子系统,而本篇则准备对于JVM运行时的内存区域以及JVM运行时的内存溢出与内存泄露问题进行全面剖析。
114 0
|
7月前
|
存储 JavaScript 前端开发
内存管理和内存泄露(闭包、作用域链)(一)
内存管理和内存泄露(闭包、作用域链)
76 0
|
7月前
|
架构师 C语言 C++
内存泄漏专题(2)如何判断程序有内存泄露
内存泄漏专题(2)如何判断程序有内存泄露
89 1
|
7月前
|
Ubuntu 架构师 Linux
内存泄露专题(5)动态内存追踪大杀器:bcc
内存泄露专题(5)动态内存追踪大杀器:bcc
162 0
|
7月前
|
架构师 Unix Linux
内存泄露专题(4)mtrace内存追踪
内存泄露专题(4)mtrace内存追踪
168 0
|
存储 缓存 监控
JVM第一讲:内存结构和内存分配,内存溢出和内存泄露
JVM第一讲:内存结构和内存分配,内存溢出和内存泄露
|
24天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
196 1