C/C++语言 浅谈C/C++内存管理知识点

首先来展示下内存区域划分图

 

这里就不介绍堆栈和数据代码区域了,相信大家都非常熟悉了,简单谈一下内存映射段

内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信

这里提一下大家总是分不清楚的sizeof和strlen

sizeof 和 strlen的区别

  • sizeof是一个运算符(部分操作时不添加不尾缀括号),其作用是返回一个对象或者类型在内存中所占的字节

  • strlen是C语言中的库函数,依赖于<string.h>头文件,其作用是求字符串的实际长度,方法是从开始直到遇到第一个'\0'结束

    函数原型unsigned int strlen(char* s)

    

数组做sizeof的参数不退化,传递给strlen就退化为指针了

eg:

    char* ss = "0123456789";

    sizeof(ss);    4

    sizeof(*ss);    1

    strlen(ss);    10

    

c语言中动态内存管理方式

malloc

    void* malloc(size_t size)

calloc

    void* calloc(size_t size, int num)

    calloc会将申请的内存大小全部初始化为0

realloc

    void* realloc(void* ptr,size_t size)

  •     realloc的功能是将ptr所指向的空间进行调整大小到Size大小的字节数

  •     如若ptr传入 的值为null则realloc的功能会和malloc相同

  •     newsize和oldsize对比,如若大不了多少,则返回的地址还为原地址,否则重新分配newsize的内存,进行拷贝操作,然后释放旧空间

malloc工作原型:https://blog.csdn.net/mmshixing/article/details/51679571

此处需要知道malloc在分配空间时会数据区在之前添加一个meta区记录数据块的元信息(数据区大小、空闲标志位、指针等)

c++语言内存管理方式

先看三个例子的区别

int* ptr1 = new int;

int* ptr2 = new int(10);//动态申请一个int类型的空间并初始化为10

int* ptr3 = new int[10];//动态申请10个int类型的空间

new的原理:

  1. 调用operator new(系统全局函数)函数申请空间

  2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理:

    1.在空间上执行析构函数,完成对象中资源的清理工作

    2.调用operator delete(系统全局函数)函数释放对象的空间

new T[N]的原理:

    1.调用operator new[]函数,实际调用operator new函数完成N个对象空间的申请

    2.在申请的空间上执行N次构造函数

void* operator new[ ](size_t size = N * sizeof(T) +4)//加4与否取决于T类是否提供析构函数

        operator new(size)

delete[]的原理

    1.在释放的对象空间上执行N次析构函数,完成N个对象中资源的a清理(从后往前)

    2.调用operator delete[]释放空间,实际调用operator delete函数完成N个对象空间的申请

在空间内上文提到的4个字节当中取对象的个数N,调用N次析构函数

void operator delete[ ] (void* p)

operator delete(p)

free(p)

    new/delete new[]/delete[] 要成套来使用 否则可能会造成崩溃或者内存泄漏(与析构处理有关)

operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功直接返回,失败则尝试执行空间不足的应对措施,如果应对措施用户设置了,则继续申请否则抛异常

operator delete:该函数最终是通过free来释放空间的

operator new( )/operator delete( ) 用户可以自己实现

返回值必须是void* , 且首参数必然为size_t size

malloc/free & new/delete 区别

1.maollc/free是函数,new/delete是操作符

2.new申请的空间可以初始化,malloc不行

3.malloc的返回值是void*,所以需要计算空间大小并传递且使用时必须更改类型,new不需要

4.malloc申请失败返回NULL,new需要捕获异常

5.malloc申请的空间一定在堆上,而new不一定,因为operator new可能会存在重载

6.new/delete比malloc/free的效率稍微低点,因为new/delete的底层封装了maolloc/free

7.malloc/free只能申请内置类型的空间,不能申请自定义类型的空间,因为其不会调用构造与析构函数

这里普及一个概念,因为我这次总结知识点时第一次看到内置类型这个关键词

内置类型:C++定义饿了一套包括算术类型(字符型,整型,bool型,浮点型)和空类型(函数运行完成之后不返回任何数值)在内的基本数据类型

定位new表达式

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象

void Text()
{
    //此时pt指向的只是一个和Test对象有着相同大小的一段空间,因为并没有实现构造函数
    //所以不能说pt就是指向了一个Text对象
    Test* pt = (Test*)malloc(sizeof(Test));
    
    //如果Test对象的构造函数需要传参时这里应当传参
    new(pt) = Test;

    delete pt;
} 

怎么禁止一个函数的拷贝构造函数:

    1.在私有里声明拷贝构造函数(C++98)

    2.Test(const Test& t ) = delete

问题:只在堆/栈上创建一个对象?

堆:    私有化声明拷贝构造和构造函数,提供一个静态成员函数完成堆上创建对象

栈:    1.屏蔽(私有化)掉new的功能(operator new/delete)

         //但全局作用域里还可以创建对象   

         2.私有化声明构造函数和拷贝构造,提供一个静态成员函数创建一个临时对象返回

         //此方法创建了多个临时对象,资源浪费

创建对象的两种方式: 

1.静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数;

2.动态建立类对象,是使用new运算符将对象建立在堆空间中。这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配;第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,间接调用类的构造函数。

猜你喜欢

转载自blog.csdn.net/ladykiller21/article/details/86496397