C/C++内存管理方式

C/C++内存管理方式_第1张图片

1.栈又叫堆栈,非静态局部变量/函数参数/返回值等,栈是向下增长的。
2.内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享内存,做进程间通信。
3.堆用于程序运行时动态内存分配,堆是向上增长的
4.数据段———存储全局数据和静态数据
5.代码段———可执行的代码/只读常量

malloc / calloc /realloc 的区别
C/C++内存管理方式_第2张图片

常见的内存泄漏

void MemoryLeaks()
{
// 1、内存申请了忘记释放
int *pTest = (int *)malloc(10*sizeof( int));
assert(NULL != pTest);
DoSomething();
//free(pTest); 忘记了释放!!!
// 2、程序逻辑不清,以为释放了,实际内存泄露
int *pTest1 = (int *)malloc(10*sizeof( int));
int *pTest2 = (int *)malloc(10*sizeof( int));
DoSomething();
pTest1 = pTest2;
free(pTest1);
free(pTest2);//pTest2申请的空间未释放!!!
// 3、程序误操作,将堆破坏
char *pTest3 = (char *)malloc(5);
strcpy(pTest3, "Memory Leaks!");//字串拷贝时越界!!!
free(pTest3);
// 4、释放时传入的地址和申请时的地方不相同
int *pTest4 = (int *)malloc(10*sizeof( int));
assert(NULL != pTest4);
pTest4[0] = 0;
pTest4++;//pTest4的指向地址已经变更!!!
DoSomething();
free(pTest4);
}

如何检测内存泄漏

1.系统自带的工具
2.自己实现检测工具
3.第三方检测工具VLD

系统自带的:
#inlcude 
void TestFunc()
{
    int* p = (int*)malloc(sizeof(int));
}
int main()
{
    TestFunc();
    _CtrDumpMemoryLead();
    return 0;
}

C++内存管理方式

new和delete运算符进行动态内存管理

  • new/delelte动态管理对象
  • new[]/delelte[]动态管理对象数组
void Test()
{
       //动态分配4个字节(1个int)的空间单个数据
       int *p1 = new int;
       //动态分配4个字节(1个int)的空间并初始化为10
       int *p2 = new int(10);
       //动态分配40个字节的空间(一片连续的空间)
       int *p3 = new int[10];
       delete p1;
       delete p2;
       delete[] p3;
}

C库malloc/free等来动态管理内存,为什么C++还要定义new/delete运算符来动态管理空间?

    malloc与free是C、C++语言的标准库函数,new/delete是C++的运算符,它们都用于申请动态内存和释放内存。
   对于非内部数据类型的对象而言,只用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译控制权限之内,不能够吧执行构造函数和析构函数的任务强加给malloc/free。
    因此c++语言需要一个能够完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delelte.new/delete不是库函数而是运算符。
   malloc只能分配动态内存,而new除了分配动态内存还能构造对象,free只能释放内存,而delete除了释放空间,还执行了析构函数。

void TestMemory()
{
int* p1 = (int*)malloc(sizeof(int));
int* p2 = (int*)malloc(sizeof(int));
delete p1;
delete[] p2; //崩溃(如果没有析构函数,就不会崩溃)
int* p3 = new int;
int* p4 = new int;
free(p3);
delete[] p4;//崩溃(如果没有析构函数,就不会崩溃)
int* p5 = new int[10];
int* p6 = new int[10];

free(p5); //崩溃(如果没有析构函数,就不会崩溃)
delete p6;//崩溃(如果没有析构函数,就不会崩溃)
}
class Test
{
public:
Test()
: _data(0)
{
cout<<"Test():"<<this<cout<<"~Test():"<<this<private:
int _data;
};

*new
C/C++内存管理方式_第3张图片

 假设new T  
1.申请空间
    void* operator new(sizeof(T));
        1.调用malloc循环申请,直到申请成功
                申请成功:返回
                申请失败:
                    检测:有没有提供内存不足的对应措施
                            提供:继续malloc
                            没提供:抛出异常
        2.调用构造函数

delete

1.调用析构函数
将指针所指向对象中的资源清理掉
2.释放空间
void operator delete(void* p)
依靠free

new T[N]

  1. void* operator new[](size_t count = N * sizeof(T) +4)
    注意:上面那个4,有析构函数时才加。(这4个字节的内存里存的是申请空间的大小)
    调用 operator new(count)
    调malloc:循环申请空间
    申请成功:返回
    申请失败:检测空间不足应对措施
    2.调用N次构造函数

delete [ ]

假设析构函数显示给出(即会多出四个字节,要调N次析构函数)
1.销毁对象
a.从空间的前四个字节中取析构函数的调用次数N
b.调用N次析构函数析构N个对象
2.释放空间
void oprator delete[](void* p)
operator delete(p)
free(p)

重要的事情说三遍:
注意:malloc/free new/delete new[]/delete[] 一定要成对使用!!!
注意:malloc/free new/delete new[]/delete[] 一定要成对使用!!!
注意:malloc/free new/delete new[]/delete[] 一定要成对使用!!!

C/C++内存管理方式_第4张图片
自己把operator new 给出,就不会去调系统的。优先调类里面的,然后全局作用域里的,然后系统

定位new表达式

定位new表达式是在已分配的原始空间中调用构造函数初始化有个对象。
Test* pt = (Test*)malloc(sizeof(Test));
new(pt) Test;

C/C++内存管理方式_第5张图片
内存池化,先开辟一大片空间,每次要构造对象时,在这一大片空间里取拿所需要的空间。

这样做的原因:
1.多次创建对象,要多次用new,就要多次频繁调用malloc,系统提供堆的分配算法,效率低
2.每一次malloc要多占36个字节
3.每一次malloc的空间是不连续的,会造成内存碎片

你可能感兴趣的:(C++,C语言,C++,数据结构,linux笔记)