C/C++内存分布图
用户并不能使用所有的内存空间,内存空间被划分为用户态(用户自己的信息)和内核态(与系统相关的信息)
对内存区域划分的原因:便于信息和数据管理
- C++程序在执行时将内存划分成4个区域
- 划分意义:不同区域存放数据,赋予不同的生命周期,使编程更灵活
代码区 | 存放函数体的二进制代码,由操作系统进行管理 |
---|---|
全局区 | 存放全局变量,静态变量,常量 |
栈区 | 由编译器自动分配释放,存放函数参数,局部变量 |
堆区 | 由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收 |
程序在运行前只有代码区和全局区,运行后才会有栈区和堆区
内存泄漏
指程序未能释放掉不再使用的内存。
内存泄漏并不是内存在物理意义上的消失,而是程序分配某段内存后,失去了对该段内存的控制造成的
内存泄漏的分类
(1)堆内存泄漏:
程序运行时通过malloc/new等从堆中分配的一块内存,使用完成后必须通过调用相对应的free/delete释放掉。
如果这部分内存没有被释,那么这块内存不会被使用,从而导致堆内存泄漏。
(2)系统资源泄漏
程序使用系统分配的资源比如socket等没有使用相应的函数释放掉,导致系统资源的浪费
(3)没有将基类的析构函数定义为虚函数。
当基类指针指向派生类的对象时,如果基类的析构函数不是虚函数,那么子类的析构函数将不会被调用,子类的资源没有被正确释放掉,造成内存泄漏。
如何判断内存泄漏
使用linux下的内存泄漏检查工具来判断内存是否泄漏
在写代码时添加内存申请和释放的统计功能,来统计当前申请和释放的内存是否一致,从而来判断内存是否泄漏。
段错误
段错误通常发生在访问非法内存地址的时候,即使用了野指针(指向一个已删除的对象或者未申请访问受限内存区域的指针)或这试图修改字符串常量的内容。
内存溢出
内存溢出指程序在申请内存时,没有足够的内存供申请者使用
内存溢出原因
(1)内存中加载的数据量过于庞大,如一次性从数据库取出过多数据。
(2)集合类中有对对象的引用,使用后未清空,使得不能回收。
(3)代码中存在死循环或循环产生过多重复的对象实体。
(4)使用的第三方软件中的bug
(5)启动参数内存值设定的过小
栈溢出
由于递归或循环嵌套层次太多造成的
栈溢出的现象
(1)局部数组过大。当函数内部的数组过大时,有可能导致栈溢出。
(2)递归调用层次太多。递归函数在运行时会执行压栈操作,当压栈次数太多时,也会导致栈溢出。递归求第1000项的斐波那契数造成栈溢出。
(3)指针或数组越界。例如进行字符串拷贝
解决办法
1.增大栈空间
2.改用动态分配
3.使用堆而不是栈
堆溢出
不断的new 一个对象,一直创建新的对象,但是不销毁。