用一到题先小试牛刀,来理解一下内存分布
内存分段
- 栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
- 堆用于程序运行时动态内存分配,堆是可以上增长的。
- 数据段–存储全局数据和静态数据。
- 代码段–可执行的代码/只读常量。
C中的内存管理
malloc、calloc、realloc
void Test ()
{
int* p1 = (int*) malloc (sizeof (int)*4);
free(p1 ); // calloc/realloc/malloc 的区别是什么?
int* p2 = (int*) calloc(4, sizeof (int));
int* p3 = (int*) realloc(p2 , sizeof( int)*6);
// 这里需要free(p2)吗?
free(p1);
}
其他知识点:
https://blog.csdn.net/sifanchao/article/details/80247647
什么是内存泄漏
内存泄漏也称作”存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
内存泄漏形象的比喻是”操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以”内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。
如何进行内存泄露检测?
_CrtDumpMemoryLeaks()
C++内存管理方式
C语言内存管理方式在C++中可以继续使用,同时C++又提出了自己的内存管理方式:
C++中通过new和delete运算符进行动态内存管理
new/delete动态管理对象 new[]/delete[]动态管理对象数组
void Test()
{
int *p1 = new int;//单个整型的空间
int *p2 = new int(3);//初始化
int *p3 = new int[3];//一段连续的空间
int *p4 = (int *)malloc(sizeof(int));
if (NULL == p4)
return;
delete p1;
delete p2;
delete[] p3;
free(p4);
}
new和delete、new[]和delete[]一定匹配使用,一定匹配使用,一定匹配使用!!!
否则,内置类型没有影响,自定义类型会出现内存泄露甚至崩溃的问题
C库malloc/free等来动态管理内存,为什么C++还要定义new/delete运算符来动态管理内存呢?
class Test
{
public:
Test()
:_data(0)
{
cout << "Test():" << this << endl;
}
~Test()
{
cout << "~Test():" << this << endl;
}
private:
int _data;
};
int main()
{
Test *p1 = new Test;//单个整型的空间
Test *p2 = new Test[3];//一段连续的空间
Test *p3 = (Test *)malloc(sizeof(Test));
if (NULL == p3)
return 0;
delete p1;
delete[] p2;
free(p3);
system("pause");
return 0;
}
C++对象 的 new/delete需要分别调构造函数(初始化)和析构函数(清理)!!!
malloc/free和new/delete的区别和联系
- 它们都是动态管理内存的入口
- malloc/free是C/C++标准库的函数,new/delete是C++操作符
- malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员)
- malloc/free需要手动计算类型大小且返回值会void*,new/delete可自己计算类型的大小,返回对应类型 的指针
- malloc失败返回0,new失败了会抛异常
new操作符&操作符new
- new操作符 :new/delete 表达式是C++用来动态管理内存的关键字
- 操作符new :操作符new是一个函数:
void * operator new (size_t size);
void operator delete (size_t size)
void * operator new void
operator delete[] (size_t size)
总结:
- operator new/operator delete、 operator new[]/operator delete[] 和 malloc/free用法一样
- 他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象> - 实际operator new 和operator delete只是malloc和free的一层封装
- new做了两件事
- 调用operator new分配空间。
- 调用构造函数初始化对象。
- delete也做了两件事
- 调用析构函数清理对象
- 调用operator delete释放空间
- new[N]
- 调用operator new分配空间。
- 调用N次构造函数分别初始化每个对象。
- delete[]
- 调用N次析构函数清理对象。(思考这里怎么N是怎么来的?) 其实是编译器在new出的数组对象头指 针位置向前4个字节中记录了对象个数(4个字节对应一个int值),结合内存变化观察下这种情况。
- 调用operator delete释放空间
内存池
频繁的使用new或new[]或者malloc在堆上开辟空间,除了可能出现内存泄漏,还可能出现内存碎片,造成资源的浪费。
因此,我们使用内存池的思想处理编程时需要频繁开辟内存的想法。
内存池
则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。