C++ 内存管理

第二章 内存管理

内存五大分区

重温

malloc

calloc

realloc

free

C++内存管理方式

new/delete操作内置类型

new/delete操作自定义类型

operator new 和 operator delete

定位new(placement new)


内存五大分区


五大内存分区是指计算机内存(RAM)在程序运行时被划分为五个不同的区域,分别是代码段(text segment)、数据段(data segment)、BSS段、堆(heap)和栈(stack)。这种划分方式是在传统的C语言内存模型中提出的,现在已经成为了计算机科学中的基础知识之一。

这五个内存分区的主要特点和用途如下:

  1. 代码段(text segment):存储程序的指令代码,也称为文本段或代码段。这些指令被处理器执行,控制程序的运行。

  2. 数据段(data segment):存储已初始化的全局变量和静态变量,包括全局变量、静态变量和常量数据等。这些变量在程序运行期间可以被读取和修改。

  3. BSS段:存储未初始化的全局变量和静态变量,也称为未初始化数据段(uninitialized data segment)。这些变量在程序运行前被初始化为0或者空指针,然后在程序运行期间可以被读取和修改。

  4. 堆(heap):动态分配内存的区域,用于存储程序运行时动态分配的内存块。程序员可以通过调用malloc()、realloc()等函数在堆上分配内存。

  5. 栈(stack):存储函数调用时的局部变量和函数参数,以及函数调用的上下文信息,例如函数返回地址和寄存器的值等。栈是由系统自动分配和释放的,每当函数被调用时,栈就会分配一段内存空间,函数返回后栈就会自动释放这段空间。

这五大内存分区在程序运行期间发挥着不同的作用,了解它们的特点和用途对于程序员编写高效、安全的代码非常重要。

注意

        代码段也称为文本段(text segment)是程序中存放机器指令的内存区域,包含程序执行的指令和常量数据(如字符串常量)

代码段通常是只读的,因为程序在运行时不应该修改代码段中的指令。此外,代码段通常是共享的,这意味着多个进程可以共享同一份代码段,从而实现代码的共享和节约内存的效果。

在一些系统中,代码段也可能包含一些只读的数据(如常量或只读的变量),这些数据可以在运行时被访问但不能被修改。

总的来说,代码段包含了程序执行所需的指令和常量数据,并且通常是只读和共享的。

        数据段也称为已初始化数据段(initialized data segment),是程序中存放静态和全局变量的内存区域,它包含了程序在编译时就已经分配好了内存的变量和常量数据,它存储已经被初始化的全局变量和静态变量,包括常量数据。这些变量在程序运行期间可以被读取和修改,数据段通常是可读写的。

        BSS段也称为未初始化数据段(uninitialized data segment),它存储未初始化的全局变量和静态变量。BSS段在程序运行前会被初始化为0或空指针,然后在程序运行期间可以被读取和修改。BSS段通常是可读写的。

这些术语通常用于描述传统的C语言内存模型中的内存布局,而不同的编程语言和操作系统可能会采用不同的术语和内存布局。

        常量区通常被认为是数据段的一部分,属于五大内存分区中的数据段(data segment)。数据段包括已初始化的全局变量、静态变量和常量数据,这些数据在程序运行期间可以被读取和修改。常量区存储的是不可修改的常量数据,通常在程序运行期间不会被修改,因此常量区也被视为数据段的只读部分。

来道题

        

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
    static int staticVar = 1;
    int localVar = 1;
    int num1[10] = { 1, 2, 3, 4 };
    char char2[] = "abcd";
    const char* pChar3 = "abcd";
    int* ptr1 = (int*)malloc(sizeof(int) * 4);
    int* ptr2 = (int*)calloc(4, sizeof(int));
    int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
    free(ptr1);
    free(ptr3);
}

1. 选择题:
选项: A.栈  B.堆  C.数据段  D.代码段
globalVar在哪里?____C  staticGlobalVar在哪里?____C
staticVar在哪里?____C  localVar在哪里?____A
num1 在哪里?____A
char2在哪里?____A  *char2在哪里?___A
pChar3在哪里?____A    *pChar3在哪里?____D
ptr1在哪里?____A     *ptr1在哪里?____B
2. 填空题:
sizeof(num1) = ____;40 
sizeof(char2) = ____;5    strlen(char2) = ____;4
sizeof(pChar3) = ____;4或8   strlen(pChar3) = ____;4
sizeof(ptr1) = ____;4或8

重温


C语言的三种动态内存管理的函数

malloc

        申请指定大小的空间(未初始化,随机值)

int* pi = (int*)malloc(sizeof(int) * 1);  //申请一个整型
double* pd = (double*)malloc(sizeof(double) * 2); //申请两个浮点型
char* pc = (char*)malloc(sizeof(char) * 3); //申请三个字符型

calloc

        申请的空间初始化为 0

int* pi = (int*)calloc(1, sizeof(int)); //申请一个整型
double* pd = (double*)calloc(2, sizeof(double));  //申请两个个浮点型
char* pc = (char*)calloc(3, sizeof(char));  //申请三个字符型

realloc

        对已申请的空间进行扩容

int* tmp = (int*)realloc(pi, sizeof(int) * 10); //将 pi 扩容为十个整型

注意:

        我们要对所有的申请函数进行空指针检查,预防野指针问题

凡是动态开辟的空间,用完后都需要释放

free

free(tmp);  //此时tmp指向pi扩容后的空间,释放tmp就行了
tmp = NULL;   // 置空
free(pd);
pd = NULL;
free(pc); //只要是动态开辟的,都需要通过 free 释放
pc = NULL;

注意:

        只有动态开辟的空间才能使用 free,同一块空间不能释放两次。我们在 free 后通常会把指针置空

        C语言 中管理函数只能对内置类型使用,而 C++ 中存在很多自定义类型,常规 malloc 等函数无能为力

C++内存管理方式


通过new和delete操作符进行动态内存管理

        使用new是动态分配内存,这个分配的是堆的内存,需要用户自己手动释放,即通过delete释放;而不使用new的对象在栈的空间中,在当前作用于结束后自动回收。

        new创建出的对象需要使用指针接收。

new/delete操作内置类型


    int* ptr1 = new int;//动态开辟一个int空间
    delete ptr1;
    int* ptr2 = new int(10);//动态申请一个int类型的空间并初始化为10
    delete ptr2;
    int* ptr3 = new int[3];//申请3个int类型的空间
    delete[] ptr3;
    int* ptr4 = new int[3] {1, 2, 3};//申请3个int类型的空间并进行初始化
    delete[] ptr4;

        申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用
new[]和delete[],注意:需要配套使用

new/delete操作自定义类型

        在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与
free不会

class A
{
public:
    A(int a = 0)
        :_a(a)
    {
        cout << "A():" << this << endl;
    }
    ~A()
    {
        cout << "~A():" << this << endl;
    }
private:
    int _a;
};
int main()
{
    // new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数
    A* p1 = (A*)malloc(sizeof(A));
    A* p2 = new A(1);
    free(p1);
    delete p2;
    // 内置类型是几乎是一样的
    int* p3 = (int*)malloc(sizeof(int)); // C
    int* p4 = new int;
    free(p3);
    delete p4;
    A* p5 = (A*)malloc(sizeof(A) * 10);
    A* p6 = new A[10];
    free(p5);
    delete[] p6;
    return 0;
}

operator new 和 operator delete


        new 和 delete 是用户进行动态内存申请和释放的 操作符,它们在实现时会去调用真正的全局函数 operator new 与 operator delete,operator new 和operator delete是系统提供的全局函数。

        operator new 实际也是通过malloc来申请空间

        operator delete 最终是通过free来释放空间的

只是在 开辟或释放 失败时会抛出异常。

定位new(placement new)


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

    A* p1 = (A*)malloc(sizeof(A));
    if (p1 == nullptr)
    {
        perror("malloc fail");
        exit(-1);
    }

    // 定位new -- 对p3指向空间,显示调用构造函数初始化
    new(p1)A(1);
    delete p1;
    return 0;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值