前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C/C++内存管理

C/C++内存管理

作者头像
Kevin_17
发布2024-05-24 14:09:41
390
发布2024-05-24 14:09:41
举报
文章被收录于专栏:Base_CDNKevinBase_CDNKevin

引言

C/C++作为广泛使用的系统级编程语言,提供了直接操控内存的能力,这也意味着开发者需要对内存管理有深刻的理解。本文旨在深入浅出地讲解C/C++内存管理机制,包括内存分布、动态内存分配与释放、以及内存管理的最佳实践。

内存分布图解

image.png
image.png

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

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

  1. malloc:
    • void* malloc(size_t size);
    • 功能:malloc函数用于在堆上分配一块连续的内存空间。它接受一个参数,即所需内存的大小(以字节为单位),并返回指向这块内存的指针。
    • 初始化:malloc不会对分配的内存进行初始化,内存中的内容是未定义的,可能是之前的值或者全零,具体取决于操作系统。
    • 使用场景:当不需要初始化内存或者特定初始化时使用。
  2. calloc:
    • void* calloc(size_t num, size_t size);
    • 功能:calloc也用于在堆上分配内存,但它接受两个参数,分别是要分配的元素数量和每个元素的大小(以字节为单位)。calloc会确保分配的内存区域中的每个字节都被初始化为零。
    • 初始化:与malloc不同,calloc会将分配的内存全部初始化为零,这使得它适合用于数组或结构体等需要初始化为默认值的情况。
    • 使用场景:当需要一个清零的内存块时使用,比如初始化数组。
  3. realloc:
    • void* realloc(void* ptr, size_t size);
    • 功能:realloc用于调整先前通过malloc、calloc或realloc分配的内存块的大小。它接受两个参数,第一个是之前分配的内存的指针,第二个是新的大小(可以比原来大也可以比原来小)。
    • 初始化:realloc不涉及初始化新分配的内存部分,如果扩大了内存块,新增的部分通常也是未定义的值。
    • 使用场景:当原先分配的内存大小不再满足需求,需要扩大或减小内存空间时使用。需要注意的是,如果减小内存空间,超出新大小的部分数据会被截断。

C++内存管理方式

对于C语言内存管理方式上的一些无法解决的地方和不方便使用的地方,C++进行优化,形成C++的内存管理机制。

new/delete操作内置类型

使用方式:

代码语言:javascript
复制
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请10个int类型的空间
int* ptr6 = new int[10];

delete ptr4;
delete ptr5;
delete[] ptr6;

图示规则:

image.png
image.png

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

  • 尽量匹配使用

new和delete操作自定义类型

  • new和delete相比叫malloc和free在操作自定义类型上最大的区别就是对于自定义类型除了开辟空间,还会调用构造函数和析构函数。
  • 对于内置类型几乎操作一样

operator new与operator delete函数

operator new与operator delete的源码剖析可以发现:

newdelete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间

  • operator new在全局函数中实际是通过:malloc申请空间
  • operator delete在全局函数中实际是通过:free销毁空间

new和delete的实现原理

内置类型

申请的是内置类型的空间,new和malloc,delete和free基本类似 ,不同的地方是:new在申请空间失败时会抛异常,malloc会返回NULL。

自定义类型

  • new的原理
    • new会首先会调用operator new函数来申请空间(malloc)
    • 然后再调用自定义类型的构造函数,在开辟的空间上执行构造函数,完成对象的构造
  • delete的原理
    • delete会先执行析构函数,将当前对象中的资源进行=清理
    • 后调用operaor delete函数进行释放对象创建时开辟的空间(free)
  • new T[N]的原理
    • 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
    • 在申请的空间上执行N次构造函数
  • delete[]的原理
    • 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
    • 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

定位new表达式(placement-new)

定位new表达式(Placement New Expression),或简称placement new,是C++中一种特殊的内存分配方式,它允许你在已经分配好的内存区域内构造对象。与标准的new操作符不同,定位new不负责内存的分配,而是直接在你指定的内存地址上调用对象的构造函数。这对于实现内存池、重复利用已分配的内存块、在特定内存位置(如共享内存)创建对象等场景非常有用

使用格式

  • new (place_address) type或者
  • new (place_address) type(initializer-list)

place_address必须是一个指针,initializer-list是类型的初始化列表

示例

我们现在开辟一块与A类相同大小的空间

代码语言:javascript
复制
A* p1 = (A*)malloc(sizeof(A));

使用定位new对已有的空间p1调用A的构造函数进行初始化

代码语言:javascript
复制
new(p1)A;

注意事项

  1. 内存管理:使用定位new后,对象的生命周期管理完全由程序员负责。这意味着你不能使用普通的delete来释放这个对象,因为那会试图释放由malloc分配的内存,导致未定义行为。你应该直接调用对象的析构函数,并手动归还内存(如果适用):
代码语言:javascript
复制
A->~A(); // 手动调用析构函数
std::free(p1); // 释放内存

  1. 内存对齐:确保提供的内存地址是正确对齐的,以便能够容纳特定类型的对象。如果不对齐,可能导致未定义行为。
  2. 安全性:使用定位new时,你需要确保所指定的内存区域足够大,以容纳完整的对象实例,包括可能的内部对齐填充。否则,可能会覆盖周边内存,引发严重错误。
  3. 标准库支持:C++标准库提供了一个全局的operator new(void*, std::size_t)重载,它不执行任何实际的内存分配,专门用于定位new表达式。这个重载是固定的,不能被用户自定义版本替代。

常见面试题

malloc/free和new/delete的区别

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。 不同的地方是:

  1. malloc和free是函数,new和delete是操作符
  2. malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[]中指定对象个数即可
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间 后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 内存分布图解
  • C语言中动态内存管理方式
  • C++内存管理方式
    • new/delete操作内置类型
      • new和delete操作自定义类型
      • operator new与operator delete函数
      • new和delete的实现原理
        • 内置类型
          • 自定义类型
          • 定位new表达式(placement-new)
            • 使用格式
              • 示例
                • 注意事项
                • 常见面试题
                  • malloc/free和new/delete的区别
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档