C++内存管理(区别C语言)深度对比

简介: C++内存管理(区别C语言)深度对比

前言

前面已经介绍了类和对象,对C++面向对象编程已经有了全面认识,接下来要学习对语言学习比较重要的是对内存的管理。

一、内存的分区

  1. 代码区:存放程序的机器指令,通常是可共享的,并且通常为只读的,以防止程序意外修改自身的代码。
  2. 全局/静态存储区:存放全局变量和静态变量,这些变量在程序的整个生命周期内都存在。
  3. 堆区:用于动态分配内存,程序运行时根据需要通过malloc、calloc、realloc等函数在堆区中分配内存空间。
  4. 栈区:存放函数的局部变量和函数调用的参数,由编译器自动管理,遵循后进先出的原则。
  5. 常量区:存放常量数据,如字符串字面量,这些数据在程序运行期间不可修改。
  6. 代码区:存放程序的二进制代码,是程序执行指令的存储空间。

二、C语言中的内存管理(参考)

  • malloc函数用于动态分配指定大小的内存空间,并返回指向该内存的指针。如果分配成功,返回非NULL指针;否则返回NULL。
  • calloc函数除了分配内存外,还会将分配的内存初始化为零。
  • realloc函数用于调整已分配内存的大小,可能会移动内存块以适应新的大小要求。
  • free函数用于释放之前通过动态内存分配函数分配的内存空间

三、C++中的内存管理

C++内存分配

不同于C语言,C++有着自己独立动态内存开辟的方法:

主要通过newdelete操作符来实现new操作符用于分配单个对象或数组,而deletedelete[]分别用于释放这些对象或数组所占用的内存.

下面是new和delete应用的实例:

 //动态申请一个int大小空间
int* p0 = new int;
//动态申请一个int大小空间并且初始化为0
int* p1 = new int (0);
//动态申请10个int大小空间
int* p2 = new int[10];
//动态申请10个int大小空间并且初始化为0
int* p3 = new int[10] {0};

delete p0;
delete p1;
delete[] p2;
delete[] p3; 

注意

  1. 不要使用delete释放非new开辟的空间
  2. 不要使用delete释放同一块空间两次
  3. 如果使用new [ ] 开辟数组进行内存分配,应该使用delete [ ] 来释放
  4. 如果new对一个实体进行内存分配,应该使用delete(没有方括号)进行释放

四、new 和 delete深度探索

有关operator new 和operator delete

operator new

  • operator new是一个特殊的操作符,用于动态分配内存。它与new操作符密切相关,但它们在语义上有所区分。
  • new操作符是一个高级操作符,它不仅分配内存,还自动调用对象的构造函数。
  • operator new仅负责分配内存,不涉及对象的构造。
  • operator new可以被重载,以便为特定的类或全局范围提供自定义的内存分配策略
  • operator new:该函数实际通过``malloc来申请空间,当malloc`申请空间成功时直接返回
  • 申请空间失败, 尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。

通俗的讲 ,new 不仅仅可以进行空间开辟,针对自定义类型会调用其构造函数,而new也是调用重载(operator new),进行内存的分配,然而 operator new 进行内存分配是通过malloc进行实现的,这正是区别于C语言的其中一点。

关于时间类和汇编语言:

class Date
{
public:
  Date(int year = 1,int month = 1,int day = 1)
    :_year(year)
    ,_month(month)
    ,_day(day)
  {}
  ~Date()
  {
    _year = 0;
    _month = 0;
    _day = 0;
  }

private:
  int _year = 1;
  int _month = 1;
  int _day = 1;
};

  Date* d1 = new Date;
00007FF62A0D19FC  mov         ecx,0Ch  
00007FF62A0D1A01  call        operator new (07FF62A0D103Ch)  。//调用operator new内存分配
00007FF62A0D1A06  mov         qword ptr [rbp+108h],rax  
00007FF62A0D1A0D  cmp         qword ptr [rbp+108h],0  
00007FF62A0D1A15  je          main+5Dh (07FF62A0D1A3Dh)  
00007FF62A0D1A17  mov         r9d,1  
00007FF62A0D1A1D  mov         r8d,1  
00007FF62A0D1A23  mov         edx,1  
00007FF62A0D1A28  mov         rcx,qword ptr [rbp+108h]  
00007FF62A0D1A2F  call        Date::Date (07FF62A0D13D4h)    // 调用构造函数
00007FF62A0D1A34  mov         qword ptr [rbp+118h],rax  
00007FF62A0D1A3B  jmp         main+68h (07FF62A0D1A48h)  
00007FF62A0D1A3D  mov         qword ptr [rbp+118h],0  
00007FF62A0D1A48  mov         rax,qword ptr [rbp+118h]  
00007FF62A0D1A4F  mov         qword ptr [rbp+0E8h],rax  
00007FF62A0D1A56  mov         rax,qword ptr [rbp+0E8h]  
00007FF62A0D1A5D  mov         qword ptr [d1],rax 

operator delete

  • operator delete 是一个全局函数,用于释放之前通过 operator new 分配的内存。
  • 它是 new 操作符的逆运算,负责在内存释放时执行必要的清理工作。
  • operator delete 通常在 delete 表达式中被隐式调用,用于释放单个对象或对象数组的内存
  • 在空间上执行析构函数,完成对象中资源的清理工作
  • 调用operator delete函数释放对象的空间(通过free)
00B72150  push  ebp 已用时间<=1ms 
00B72151  mov ebp,esp 
00B72153  sub esp,0cCh  
00B72159  push  ebx 
00B7215A  push  esi 
00B7215B  push  edi 
00B7215C  push  ecx 
00B7215D  lea edi,[ebp-0Ch] 
00B72160  mov ecx,3 
00B72165  mov eax,0cccccccch  
00B7216A  rep stos  dword ptr es:[edi]  
00B7216C  pop ecx 
00B7216D  mov dword ptr [this],ecx  
00B72170  mov ecx,dword ptr [this]  
00B72173  call  A::~A (0B7154Bh)      //调用析构函数
00B72178  mov eax,dword ptr [ebp+8] 
00B7217B  and eax,1 
00B7217E  je  __call_empty_init_list_helper<A>+0Eh (0 
00B72180  push  4 
00B72182  mov eax,dword ptr [t. ebp 15990024  
00B72185  push  eax 
00B72186  call  operator delete (0B710AAh)  //释放空间
00B7218B  add esp,8 
00B7218E  mov eax,dword ptr [this]  
00B72191  pop edi 
00B72192  pop esi                                                         

小结

new 和delete 调用的时候内部调用的顺序

  • new 先进行空间的开辟(malloc),在进行对象的实例化
  • delete先进行析构函数的调用,进行资源的销毁,在进行空间的释放(free

image.png

五、replacement new

在C++中new操作符通常用于在堆上分配内存并调用对象的构造函数。除了常规的new操作符外,C++还提供了operator newplacement new两种替代机制。operator newnew操作符内部使用的函数,可以被重载以提供自定义的内存分配策略。而placement new是一种特殊的new表达式,它允许在已分配的内存上构造对象,而不是分配新的内存。

//用法
new(place_address)type

应用场景:

池化技术:

化技术在C++编程中通常指的是预先分配一定数量的资源(如内存、线程等)并存储在一个“池”中,以便在程序运行时可以快速地从中获取和返回资源,而不是每次都进行昂贵的动态分配和释放操作。

这个就是进行已有空间进行对象实例化

六、C语言和C++内存分配的区别

区别malloc free new delete

  1. mallocfree是函数,而newdelete是操作符
  2. malloc不可以初始化而new可以初始化
  3. malloc进行内存分配的时候是手动计算空间的大小,而new后面跟类型,大小在 [ ]中指定
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败是返回NULL,而new申请空间失败是捕获异常
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间 后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型

5. malloc申请空间失败是返回NULL,而new申请空间失败是捕获异常

6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间 后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

目录
相关文章
|
17天前
|
程序员 C语言 开发者
pymalloc 和系统的 malloc 有什么区别
pymalloc 和系统的 malloc 有什么区别
|
13天前
|
存储 缓存 安全
阿里云服务器内存型r7、r8a、r8y、r8i实例区别及选择参考
随着阿里云2024年金秋云创季的开始,目前在阿里云的活动中,属于内存型实例规格的云服务器有内存型r7、内存型r8a、内存型r8y和内存型r8i这几个实例规格,相比于活动内的经济型e和通用算力型u1等实例规格来说,这些实例规格等性能更强,虽然这几个实例规格的云服务器通常处理器与内存的配比为都是1:8,但是他们在处理器、存储、网络、安全等方面等性能并不是一样的,所以他们的适用场景也有着不同。本文为大家介绍内存型r7、r8a、r8y、r8i实例的性能、适用场景的区别以及选择参考。
|
13天前
|
程序员 C语言 开发者
pymalloc 和系统的 malloc 有什么区别?
pymalloc 和系统的 malloc 有什么区别?
|
23天前
|
C语言
【c语言】动态内存管理
本文介绍了C语言中的动态内存管理,包括其必要性及相关的四个函数:`malloc`、``calloc``、`realloc`和`free`。`malloc`用于申请内存,`calloc`申请并初始化内存,`realloc`调整内存大小,`free`释放内存。文章还列举了常见的动态内存管理错误,如空指针解引用、越界访问、错误释放等,并提供了示例代码帮助理解。
35 3
|
26天前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
1月前
|
存储 C语言
C语言:普通局部变量、普通全局变量、静态局部变量、静态全局变量的区别
C语言中,普通局部变量在函数内部定义,作用域仅限于该函数;普通全局变量在所有函数外部定义,作用域为整个文件;静态局部变量在函数内部定义但生命周期为整个程序运行期;静态全局变量在所有函数外部定义,但仅在定义它的文件内可见。
45 10
|
28天前
|
存储 C语言
C语言:结构体与共用体的区别
C语言中,结构体(struct)和共用体(union)都用于组合不同类型的数据,但使用方式不同。结构体为每个成员分配独立的内存空间,而共用体的所有成员共享同一段内存,节省空间但需谨慎使用。
|
1月前
|
存储 编译器 C语言
C语言函数的定义与函数的声明的区别
C语言中,函数的定义包含函数的实现,即具体执行的代码块;而函数的声明仅描述函数的名称、返回类型和参数列表,用于告知编译器函数的存在,但不包含实现细节。声明通常放在头文件中,定义则在源文件中。
|
1月前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
1月前
|
存储 编译器 C语言
C语言:数组名作为类型、作为地址、对数组名取地址的区别
在C语言中,数组名可以作为类型、地址和取地址使用。数组名本身代表数组的首地址,作为地址时可以直接使用;作为类型时,用于声明指针或函数参数;取地址时,使用取地址符 (&),得到的是整个数组的地址,类型为指向该类型的指针。